@vertesia/ui 1.1.0-dev.20260327.125707Z → 1.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 (302) hide show
  1. package/lib/esm/core/components/ComboBox.js +23 -24
  2. package/lib/esm/core/components/ComboBox.js.map +1 -1
  3. package/lib/esm/core/components/FormItem.js +2 -2
  4. package/lib/esm/core/components/FormItem.js.map +1 -1
  5. package/lib/esm/core/components/SidePanel.js +1 -1
  6. package/lib/esm/core/components/SidePanel.js.map +1 -1
  7. package/lib/esm/core/components/shadcn/collaspible.js +3 -4
  8. package/lib/esm/core/components/shadcn/collaspible.js.map +1 -1
  9. package/lib/esm/core/components/shadcn/dropdown.js +37 -12
  10. package/lib/esm/core/components/shadcn/dropdown.js.map +1 -1
  11. package/lib/esm/core/components/shadcn/filters/comboBox/DateCombobox.js +6 -6
  12. package/lib/esm/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
  13. package/lib/esm/core/components/shadcn/filters/comboBox/SelectCombobox.js +8 -7
  14. package/lib/esm/core/components/shadcn/filters/comboBox/SelectCombobox.js.map +1 -1
  15. package/lib/esm/core/components/shadcn/filters/filterBar.js +5 -3
  16. package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
  17. package/lib/esm/core/components/shadcn/filters/filters.js +1 -1
  18. package/lib/esm/core/components/shadcn/filters/filters.js.map +1 -1
  19. package/lib/esm/core/components/shadcn/radioGroup.js +1 -2
  20. package/lib/esm/core/components/shadcn/radioGroup.js.map +1 -1
  21. package/lib/esm/core/components/shadcn/switch.js +0 -1
  22. package/lib/esm/core/components/shadcn/switch.js.map +1 -1
  23. package/lib/esm/core/components/shadcn/tabs.js +2 -2
  24. package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
  25. package/lib/esm/core/components/shadcn/tooltip.js +17 -1
  26. package/lib/esm/core/components/shadcn/tooltip.js.map +1 -1
  27. package/lib/esm/core/hooks/PortalContainerProvider.js +9 -3
  28. package/lib/esm/core/hooks/PortalContainerProvider.js.map +1 -1
  29. package/lib/esm/env/index.js +5 -8
  30. package/lib/esm/env/index.js.map +1 -1
  31. package/lib/esm/features/agent/chat/AgentRightPanel.js +21 -11
  32. package/lib/esm/features/agent/chat/AgentRightPanel.js.map +1 -1
  33. package/lib/esm/features/agent/chat/AskUserWidget.js +2 -6
  34. package/lib/esm/features/agent/chat/AskUserWidget.js.map +1 -1
  35. package/lib/esm/features/agent/chat/DocumentPanel.js +8 -5
  36. package/lib/esm/features/agent/chat/DocumentPanel.js.map +1 -1
  37. package/lib/esm/features/agent/chat/DocumentTabBar.js +5 -13
  38. package/lib/esm/features/agent/chat/DocumentTabBar.js.map +1 -1
  39. package/lib/esm/features/agent/chat/ModernAgentConversation.js +57 -26
  40. package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
  41. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +20 -16
  42. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  43. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js +56 -45
  44. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  45. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +1 -1
  46. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  47. package/lib/esm/features/agent/chat/SlidingThinkingIndicator.js +3 -9
  48. package/lib/esm/features/agent/chat/SlidingThinkingIndicator.js.map +1 -1
  49. package/lib/esm/features/agent/chat/hooks/useAgentStream.js +9 -5
  50. package/lib/esm/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  51. package/lib/esm/features/agent/chat/hooks/useDocumentPanel.js +4 -0
  52. package/lib/esm/features/agent/chat/hooks/useDocumentPanel.js.map +1 -1
  53. package/lib/esm/features/facets/AgentRunnerFacetsNav.js +1 -1
  54. package/lib/esm/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  55. package/lib/esm/features/facets/DocumentsFacetsNav.js +3 -2
  56. package/lib/esm/features/facets/DocumentsFacetsNav.js.map +1 -1
  57. package/lib/esm/features/facets/RunsFacetsNav.js +8 -1
  58. package/lib/esm/features/facets/RunsFacetsNav.js.map +1 -1
  59. package/lib/esm/features/facets/WorkflowExecutionsFacetsNav.js +1 -1
  60. package/lib/esm/features/facets/WorkflowExecutionsFacetsNav.js.map +1 -1
  61. package/lib/esm/features/facets/index.js +1 -0
  62. package/lib/esm/features/facets/index.js.map +1 -1
  63. package/lib/esm/features/facets/utils/VInteractionFacet.js +5 -5
  64. package/lib/esm/features/facets/utils/VInteractionFacet.js.map +1 -1
  65. package/lib/esm/features/index.js +1 -0
  66. package/lib/esm/features/index.js.map +1 -1
  67. package/lib/esm/features/oauth/OAuthProviderConnectButton.js +85 -0
  68. package/lib/esm/features/oauth/OAuthProviderConnectButton.js.map +1 -0
  69. package/lib/esm/features/oauth/RemoteMcpConnectionButton.js +119 -0
  70. package/lib/esm/features/oauth/RemoteMcpConnectionButton.js.map +1 -0
  71. package/lib/esm/features/oauth/index.js +4 -0
  72. package/lib/esm/features/oauth/index.js.map +1 -0
  73. package/lib/esm/features/oauth/useOAuthPopup.js +89 -0
  74. package/lib/esm/features/oauth/useOAuthPopup.js.map +1 -0
  75. package/lib/esm/features/store/collections/BrowseCollectionView.js.map +1 -1
  76. package/lib/esm/features/store/collections/EditCollectionView.js +9 -2
  77. package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
  78. package/lib/esm/features/store/objects/components/ContentOverview.js +19 -7
  79. package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
  80. package/lib/esm/features/store/objects/components/useContentPanelHooks.js +35 -15
  81. package/lib/esm/features/store/objects/components/useContentPanelHooks.js.map +1 -1
  82. package/lib/esm/features/store/objects/selection/ObjectsActionContext.js +3 -3
  83. package/lib/esm/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
  84. package/lib/esm/features/store/objects/selection/SelectionActions.js +4 -3
  85. package/lib/esm/features/store/objects/selection/SelectionActions.js.map +1 -1
  86. package/lib/esm/features/store/objects/selection/actions/ExportPropertiesAction.js +11 -3
  87. package/lib/esm/features/store/objects/selection/actions/ExportPropertiesAction.js.map +1 -1
  88. package/lib/esm/features/store/objects/upload/DocumentUploadModal.js +1 -5
  89. package/lib/esm/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  90. package/lib/esm/features/user/UserInfo.js +33 -10
  91. package/lib/esm/features/user/UserInfo.js.map +1 -1
  92. package/lib/esm/i18n/locales/ar.json +81 -98
  93. package/lib/esm/i18n/locales/de.json +44 -73
  94. package/lib/esm/i18n/locales/en.json +31 -61
  95. package/lib/esm/i18n/locales/es.json +55 -79
  96. package/lib/esm/i18n/locales/fr.json +55 -81
  97. package/lib/esm/i18n/locales/it.json +55 -79
  98. package/lib/esm/i18n/locales/ja.json +46 -75
  99. package/lib/esm/i18n/locales/ko.json +44 -73
  100. package/lib/esm/i18n/locales/pt.json +55 -79
  101. package/lib/esm/i18n/locales/ru.json +58 -81
  102. package/lib/esm/i18n/locales/tr.json +46 -75
  103. package/lib/esm/i18n/locales/zh-TW.json +46 -75
  104. package/lib/esm/i18n/locales/zh.json +46 -75
  105. package/lib/esm/session/UserSession.js +2 -4
  106. package/lib/esm/session/UserSession.js.map +1 -1
  107. package/lib/esm/session/UserSessionProvider.js +22 -17
  108. package/lib/esm/session/UserSessionProvider.js.map +1 -1
  109. package/lib/esm/session/auth/composable.js +20 -2
  110. package/lib/esm/session/auth/composable.js.map +1 -1
  111. package/lib/esm/session/auth/domainRouting.js +7 -0
  112. package/lib/esm/session/auth/domainRouting.js.map +1 -0
  113. package/lib/esm/shell/login/InviteAcceptModal.js +1 -0
  114. package/lib/esm/shell/login/InviteAcceptModal.js.map +1 -1
  115. package/lib/esm/widgets/form/Form.js +2 -2
  116. package/lib/esm/widgets/form/Form.js.map +1 -1
  117. package/lib/esm/widgets/markdown/MarkdownRenderer.js +2 -1
  118. package/lib/esm/widgets/markdown/MarkdownRenderer.js.map +1 -1
  119. package/lib/esm/widgets/markdown/preprocessMathDelimiters.js +226 -0
  120. package/lib/esm/widgets/markdown/preprocessMathDelimiters.js.map +1 -0
  121. package/lib/esm/widgets/monacoEditor/MonacoEditor.js +40 -5
  122. package/lib/esm/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  123. package/lib/esm/widgets/monacoEditor/foldingProviders.js +132 -0
  124. package/lib/esm/widgets/monacoEditor/foldingProviders.js.map +1 -0
  125. package/lib/tsconfig.tsbuildinfo +1 -1
  126. package/lib/types/core/components/ComboBox.d.ts +12 -2
  127. package/lib/types/core/components/ComboBox.d.ts.map +1 -1
  128. package/lib/types/core/components/FormItem.d.ts +5 -2
  129. package/lib/types/core/components/FormItem.d.ts.map +1 -1
  130. package/lib/types/core/components/SidePanel.d.ts.map +1 -1
  131. package/lib/types/core/components/shadcn/badge.d.ts +2 -2
  132. package/lib/types/core/components/shadcn/collaspible.d.ts +3 -3
  133. package/lib/types/core/components/shadcn/collaspible.d.ts.map +1 -1
  134. package/lib/types/core/components/shadcn/dropdown.d.ts +11 -3
  135. package/lib/types/core/components/shadcn/dropdown.d.ts.map +1 -1
  136. package/lib/types/core/components/shadcn/filters/comboBox/SelectCombobox.d.ts +2 -1
  137. package/lib/types/core/components/shadcn/filters/comboBox/SelectCombobox.d.ts.map +1 -1
  138. package/lib/types/core/components/shadcn/filters/filterBar.d.ts +2 -1
  139. package/lib/types/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  140. package/lib/types/core/components/shadcn/filters/filters.d.ts.map +1 -1
  141. package/lib/types/core/components/shadcn/input.d.ts +1 -1
  142. package/lib/types/core/components/shadcn/radioGroup.d.ts.map +1 -1
  143. package/lib/types/core/components/shadcn/switch.d.ts.map +1 -1
  144. package/lib/types/core/components/shadcn/tabs.d.ts +4 -2
  145. package/lib/types/core/components/shadcn/tabs.d.ts.map +1 -1
  146. package/lib/types/core/components/shadcn/text.d.ts +1 -1
  147. package/lib/types/core/components/shadcn/tooltip.d.ts +1 -1
  148. package/lib/types/core/components/shadcn/tooltip.d.ts.map +1 -1
  149. package/lib/types/core/hooks/PortalContainerProvider.d.ts +1 -0
  150. package/lib/types/core/hooks/PortalContainerProvider.d.ts.map +1 -1
  151. package/lib/types/env/index.d.ts +2 -2
  152. package/lib/types/env/index.d.ts.map +1 -1
  153. package/lib/types/features/agent/chat/AgentChart.d.ts +1 -1
  154. package/lib/types/features/agent/chat/AgentChart.d.ts.map +1 -1
  155. package/lib/types/features/agent/chat/AgentRightPanel.d.ts +7 -2
  156. package/lib/types/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  157. package/lib/types/features/agent/chat/DocumentPanel.d.ts +2 -2
  158. package/lib/types/features/agent/chat/DocumentPanel.d.ts.map +1 -1
  159. package/lib/types/features/agent/chat/DocumentTabBar.d.ts +1 -2
  160. package/lib/types/features/agent/chat/DocumentTabBar.d.ts.map +1 -1
  161. package/lib/types/features/agent/chat/ModernAgentConversation.d.ts +5 -3
  162. package/lib/types/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  163. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +4 -2
  164. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  165. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts +4 -4
  166. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  167. package/lib/types/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  168. package/lib/types/features/agent/chat/VegaLiteChart.d.ts +1 -1
  169. package/lib/types/features/agent/chat/VegaLiteChart.d.ts.map +1 -1
  170. package/lib/types/features/agent/chat/hooks/useAgentStream.d.ts +4 -2
  171. package/lib/types/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  172. package/lib/types/features/agent/chat/hooks/useDocumentPanel.d.ts +1 -0
  173. package/lib/types/features/agent/chat/hooks/useDocumentPanel.d.ts.map +1 -1
  174. package/lib/types/features/facets/DocumentsFacetsNav.d.ts.map +1 -1
  175. package/lib/types/features/facets/RunsFacetsNav.d.ts.map +1 -1
  176. package/lib/types/features/facets/index.d.ts +1 -0
  177. package/lib/types/features/facets/index.d.ts.map +1 -1
  178. package/lib/types/features/index.d.ts +1 -0
  179. package/lib/types/features/index.d.ts.map +1 -1
  180. package/lib/types/features/oauth/OAuthProviderConnectButton.d.ts +11 -0
  181. package/lib/types/features/oauth/OAuthProviderConnectButton.d.ts.map +1 -0
  182. package/lib/types/features/oauth/RemoteMcpConnectionButton.d.ts +25 -0
  183. package/lib/types/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -0
  184. package/lib/types/features/oauth/index.d.ts +4 -0
  185. package/lib/types/features/oauth/index.d.ts.map +1 -0
  186. package/lib/types/features/oauth/useOAuthPopup.d.ts +12 -0
  187. package/lib/types/features/oauth/useOAuthPopup.d.ts.map +1 -0
  188. package/lib/types/features/store/collections/BrowseCollectionView.d.ts.map +1 -1
  189. package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
  190. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  191. package/lib/types/features/store/objects/selection/ObjectsActionContext.d.ts +3 -3
  192. package/lib/types/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
  193. package/lib/types/features/store/objects/selection/ObjectsActionSpec.d.ts +2 -1
  194. package/lib/types/features/store/objects/selection/ObjectsActionSpec.d.ts.map +1 -1
  195. package/lib/types/features/store/objects/selection/SelectionActions.d.ts +3 -3
  196. package/lib/types/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
  197. package/lib/types/features/store/objects/selection/actions/ExportPropertiesAction.d.ts.map +1 -1
  198. package/lib/types/features/user/UserInfo.d.ts +2 -1
  199. package/lib/types/features/user/UserInfo.d.ts.map +1 -1
  200. package/lib/types/session/UserSession.d.ts.map +1 -1
  201. package/lib/types/session/UserSessionProvider.d.ts +0 -1
  202. package/lib/types/session/UserSessionProvider.d.ts.map +1 -1
  203. package/lib/types/session/auth/composable.d.ts +4 -0
  204. package/lib/types/session/auth/composable.d.ts.map +1 -1
  205. package/lib/types/session/auth/domainRouting.d.ts +8 -0
  206. package/lib/types/session/auth/domainRouting.d.ts.map +1 -0
  207. package/lib/types/shell/login/InviteAcceptModal.d.ts.map +1 -1
  208. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  209. package/lib/types/widgets/markdown/preprocessMathDelimiters.d.ts +24 -0
  210. package/lib/types/widgets/markdown/preprocessMathDelimiters.d.ts.map +1 -0
  211. package/lib/types/widgets/monacoEditor/MonacoEditor.d.ts +2 -1
  212. package/lib/types/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  213. package/lib/types/widgets/monacoEditor/foldingProviders.d.ts +2 -0
  214. package/lib/types/widgets/monacoEditor/foldingProviders.d.ts.map +1 -0
  215. package/lib/vertesia-ui-core.js +1 -1
  216. package/lib/vertesia-ui-core.js.map +1 -1
  217. package/lib/vertesia-ui-env.js +1 -1
  218. package/lib/vertesia-ui-env.js.map +1 -1
  219. package/lib/vertesia-ui-features.js +1 -1
  220. package/lib/vertesia-ui-features.js.map +1 -1
  221. package/lib/vertesia-ui-i18n.js +1 -1
  222. package/lib/vertesia-ui-i18n.js.map +1 -1
  223. package/lib/vertesia-ui-layout.js +1 -1
  224. package/lib/vertesia-ui-layout.js.map +1 -1
  225. package/lib/vertesia-ui-session.js +1 -1
  226. package/lib/vertesia-ui-session.js.map +1 -1
  227. package/lib/vertesia-ui-shell.js +1 -1
  228. package/lib/vertesia-ui-shell.js.map +1 -1
  229. package/lib/vertesia-ui-widgets.js +1 -1
  230. package/lib/vertesia-ui-widgets.js.map +1 -1
  231. package/package.json +15 -15
  232. package/src/core/components/ComboBox.tsx +66 -29
  233. package/src/core/components/FormItem.tsx +9 -6
  234. package/src/core/components/SidePanel.tsx +5 -3
  235. package/src/core/components/shadcn/collaspible.tsx +5 -7
  236. package/src/core/components/shadcn/dropdown.tsx +68 -13
  237. package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +6 -6
  238. package/src/core/components/shadcn/filters/comboBox/SelectCombobox.tsx +14 -7
  239. package/src/core/components/shadcn/filters/filterBar.tsx +5 -3
  240. package/src/core/components/shadcn/filters/filters.tsx +1 -0
  241. package/src/core/components/shadcn/radioGroup.tsx +1 -3
  242. package/src/core/components/shadcn/switch.tsx +0 -2
  243. package/src/core/components/shadcn/tabs.tsx +15 -2
  244. package/src/core/components/shadcn/tooltip.tsx +20 -3
  245. package/src/core/hooks/PortalContainerProvider.tsx +11 -3
  246. package/src/env/index.ts +7 -10
  247. package/src/features/agent/chat/AgentRightPanel.tsx +43 -23
  248. package/src/features/agent/chat/DocumentPanel.tsx +21 -19
  249. package/src/features/agent/chat/DocumentTabBar.tsx +21 -32
  250. package/src/features/agent/chat/ModernAgentConversation.tsx +72 -27
  251. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +21 -9
  252. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +136 -115
  253. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +0 -3
  254. package/src/features/agent/chat/hooks/useAgentStream.ts +13 -7
  255. package/src/features/agent/chat/hooks/useDocumentPanel.ts +8 -0
  256. package/src/features/facets/AgentRunnerFacetsNav.tsx +1 -1
  257. package/src/features/facets/DocumentsFacetsNav.tsx +3 -1
  258. package/src/features/facets/RunsFacetsNav.tsx +9 -1
  259. package/src/features/facets/WorkflowExecutionsFacetsNav.tsx +1 -1
  260. package/src/features/facets/index.ts +1 -0
  261. package/src/features/facets/utils/VInteractionFacet.tsx +12 -12
  262. package/src/features/index.ts +1 -0
  263. package/src/features/oauth/OAuthProviderConnectButton.tsx +125 -0
  264. package/src/features/oauth/RemoteMcpConnectionButton.tsx +274 -0
  265. package/src/features/oauth/index.ts +3 -0
  266. package/src/features/oauth/useOAuthPopup.ts +125 -0
  267. package/src/features/store/collections/BrowseCollectionView.tsx +3 -3
  268. package/src/features/store/collections/EditCollectionView.tsx +10 -1
  269. package/src/features/store/objects/components/ContentOverview.tsx +108 -87
  270. package/src/features/store/objects/components/useContentPanelHooks.ts +50 -15
  271. package/src/features/store/objects/selection/ObjectsActionContext.tsx +5 -5
  272. package/src/features/store/objects/selection/ObjectsActionSpec.ts +2 -1
  273. package/src/features/store/objects/selection/SelectionActions.tsx +6 -5
  274. package/src/features/store/objects/selection/actions/ExportPropertiesAction.tsx +12 -3
  275. package/src/features/user/UserInfo.tsx +82 -10
  276. package/src/i18n/locales/ar.json +81 -98
  277. package/src/i18n/locales/de.json +44 -73
  278. package/src/i18n/locales/en.json +31 -61
  279. package/src/i18n/locales/es.json +55 -79
  280. package/src/i18n/locales/fr.json +55 -81
  281. package/src/i18n/locales/it.json +55 -79
  282. package/src/i18n/locales/ja.json +46 -75
  283. package/src/i18n/locales/ko.json +44 -73
  284. package/src/i18n/locales/pt.json +55 -79
  285. package/src/i18n/locales/ru.json +58 -81
  286. package/src/i18n/locales/tr.json +46 -75
  287. package/src/i18n/locales/zh-TW.json +46 -75
  288. package/src/i18n/locales/zh.json +46 -75
  289. package/src/session/UserSession.ts +2 -5
  290. package/src/session/UserSessionProvider.tsx +23 -18
  291. package/src/session/auth/auth-flow.md +1 -1
  292. package/src/session/auth/composable.ts +21 -2
  293. package/src/session/auth/domainRouting.test.ts +26 -0
  294. package/src/session/auth/domainRouting.ts +13 -0
  295. package/src/shell/login/InviteAcceptModal.tsx +1 -0
  296. package/src/widgets/form/Form.tsx +2 -2
  297. package/src/widgets/markdown/MarkdownRenderer.tsx +2 -1
  298. package/src/widgets/markdown/markdown.css +12 -0
  299. package/src/widgets/markdown/preprocessMathDelimiters.test.ts +87 -0
  300. package/src/widgets/markdown/preprocessMathDelimiters.ts +229 -0
  301. package/src/widgets/monacoEditor/MonacoEditor.tsx +47 -4
  302. package/src/widgets/monacoEditor/foldingProviders.ts +122 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/ui",
3
- "version": "1.1.0-dev.20260327.125707Z",
3
+ "version": "1.1.0",
4
4
  "description": "Vertesia UI components and and hooks",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -24,6 +24,7 @@
24
24
  "@floating-ui/react": "^0.27.11",
25
25
  "@monaco-editor/react": "^4.7.0",
26
26
  "@radix-ui/react-checkbox": "^1.3.1",
27
+ "@radix-ui/react-collapsible": "^1.1.12",
27
28
  "@radix-ui/react-dialog": "^1.1.13",
28
29
  "@radix-ui/react-dismissable-layer": "^1.1.11",
29
30
  "@radix-ui/react-dropdown-menu": "^2.1.16",
@@ -32,12 +33,12 @@
32
33
  "@radix-ui/react-label": "^2.1.6",
33
34
  "@radix-ui/react-popover": "^1.1.13",
34
35
  "@radix-ui/react-portal": "^1.1.9",
36
+ "@radix-ui/react-radio-group": "^1.3.8",
35
37
  "@radix-ui/react-separator": "^1.1.6",
36
38
  "@radix-ui/react-slot": "^1.2.2",
39
+ "@radix-ui/react-switch": "^1.2.6",
37
40
  "@radix-ui/react-tabs": "^1.1.11",
38
41
  "@radix-ui/react-tooltip": "^1.2.6",
39
- "@radix-ui/react-radio-group": "^1.3.8",
40
- "@radix-ui/react-switch": "^1.2.6",
41
42
  "ajv": "^8.17.1",
42
43
  "ajv-formats": "^3.0.1",
43
44
  "aria-hidden": "^1.2.6",
@@ -47,10 +48,10 @@
47
48
  "dayjs": "^1.11.19",
48
49
  "debounce": "^2.2.0",
49
50
  "dompurify": "^3.3.2",
50
- "fast-xml-parser": "^5.5.7",
51
+ "fast-xml-parser": "^5.7.2",
51
52
  "firebase": "^10.12.2",
52
53
  "framer-motion": "^12.23.12",
53
- "i18next": "^25.8.14",
54
+ "i18next": "^26.0.1",
54
55
  "jwt-decode": "^4.0.0",
55
56
  "katex": "^0.16.28",
56
57
  "lodash-es": "^4.17.23",
@@ -59,13 +60,12 @@
59
60
  "monaco-editor": "^0.52.2",
60
61
  "motion": "^12.12.1",
61
62
  "papaparse": "^5.5.3",
62
- "radix-ui": "^1.4.3",
63
63
  "react": "^19.2.3",
64
64
  "react-calendar": "^6.0.0",
65
65
  "react-date-picker": "^12.0.1",
66
66
  "react-dom": "^19.2.3",
67
67
  "react-error-boundary": "^6.0.0",
68
- "react-i18next": "^16.5.5",
68
+ "react-i18next": "^17.0.2",
69
69
  "react-markdown": "^10.1.0",
70
70
  "react-pdf": "^10.2.0",
71
71
  "react-remove-scroll": "^2.7.1",
@@ -86,10 +86,10 @@
86
86
  "vega": "^6.2.0",
87
87
  "vega-embed": "^7.1.0",
88
88
  "vega-lite": "^6.4.1",
89
- "@vertesia/client": "1.1.0-dev.20260327.125707Z",
90
- "@vertesia/common": "1.1.0-dev.20260327.125707Z",
91
- "@vertesia/fusion-ux": "1.1.0-dev.20260327.125707Z",
92
- "@vertesia/json": "1.1.0-dev.20260327.125707Z"
89
+ "@vertesia/fusion-ux": "1.1.0",
90
+ "@vertesia/json": "1.1.0",
91
+ "@vertesia/common": "1.1.0",
92
+ "@vertesia/client": "1.1.0"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@eslint/compat": "^2.0.2",
@@ -100,7 +100,7 @@
100
100
  "@rollup/plugin-terser": "^0.4.4",
101
101
  "@types/hast": "^3.0.4",
102
102
  "@types/lodash-es": "^4.17.12",
103
- "@types/node": "^22.19.2",
103
+ "@types/node": "^25.6.0",
104
104
  "@types/papaparse": "^5.5.2",
105
105
  "@types/react": "^19.2.3",
106
106
  "@types/react-dom": "^19.2.3",
@@ -109,11 +109,11 @@
109
109
  "eslint-plugin-import": "^2.32.0",
110
110
  "eslint-plugin-react": "^7.37.5",
111
111
  "eslint-plugin-react-hooks": "^7.0.1",
112
- "i18next-parser": "^9.4.0",
112
+ "i18next-cli": "^1.51.5",
113
113
  "rimraf": "^6.1.2",
114
114
  "rollup": "^4.59.0",
115
- "typescript": "^5.9.3",
116
- "typescript-eslint": "^8.56.1",
115
+ "typescript": "^6.0.2",
116
+ "typescript-eslint": "^8.58.1",
117
117
  "vitest": "^4.0.16"
118
118
  },
119
119
  "exports": {
@@ -1,10 +1,10 @@
1
- import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
1
+ import { ChevronDownIcon, ChevronUpIcon, XIcon } from 'lucide-react';
2
2
  import clsx from 'clsx';
3
3
  import React, { ReactNode, useEffect, useRef, useState } from 'react';
4
4
  import { AlignType, Popup, PopupController } from "./popup/index";
5
5
 
6
- const INPUT_UNSTYLED = "block m-0 p-0 border-0 focus:outline-none focus:ring-0 bg-transparent"
7
- const INPUT_NO_PADDING = "block sm:text-sm sm:leading-6 rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-slate-600 dark:text-slate-50 dark:bg-slate-800 placeholder:text-gray-400 dark:placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 dark:focus:ring-indigo-800"
6
+ const INPUT_UNSTYLED = "block m-0 p-0 border-0 focus:outline-none focus:ring-0";
7
+ const INPUT_NO_PADDING = "block sm:text-sm sm:leading-6 bg-muted rounded-md border-0 shadow-sm ring-1 ring-inset ring-muted placeholder:text-muted focus:ring-2 focus:ring-inset focus:ring-primary"
8
8
  const INPUT = INPUT_NO_PADDING + " py-1.5";
9
9
  const COMBOBOX_POPUP = "combobox-popup";
10
10
 
@@ -66,7 +66,7 @@ export function getDefaultComboBoxLayout<T>(fullWidth?: boolean, unstyledInput?:
66
66
  buttonRight: 4,
67
67
  buttonWidth: 24,
68
68
  maxMenuHeight: 240,
69
- menuClass: "w-72 bg-white mt-1 shadow-md border border-gray-200 overflow-auto p-0 z-10",
69
+ menuClass: "w-72 mt-1 border-popover bg-popover text-popover-foreground shadow-md overflow-auto p-0 z-10",
70
70
  inputClass: clsx(unstyledInput ? INPUT_UNSTYLED : INPUT, fullWidth ? "w-full" : "!w-auto"),
71
71
  optionClass: "py-2 px-3 shadow-sm flex flex-col [&.option-selected]:font-semibold [&.option-highlighted]:bg-blue-300",
72
72
  Input: ComboInput<T>,
@@ -84,7 +84,7 @@ export interface ComboBoxApi<T> {
84
84
  setInputValue: (value: string) => void;
85
85
  focus: () => void;
86
86
  }
87
- interface ComboBoxProps<T> {
87
+ export interface ComboBoxProps<T> {
88
88
  items: T[];
89
89
  adapter: OptionAdapter<T>;
90
90
  // if true then the default layout will use an unstyled input
@@ -103,8 +103,14 @@ interface ComboBoxProps<T> {
103
103
  focusOnMount?: boolean
104
104
  menuGap?: number;
105
105
  menuAlign?: AlignType;
106
+ // show X button to clear the current selection
107
+ clearable?: boolean;
108
+ // shown inside the dropdown when filter produces zero results
109
+ noMatchMessage?: ReactNode;
110
+ // open the menu when the input is focused
111
+ openOnFocus?: boolean;
106
112
  }
107
- export function ComboBox<T>({ menuAlign = "fill", menuGap, focusOnMount, onSelect, value, zIndex, unstyledInput, fullWidth, api, layout: layoutOpts, adapter, items, placeholder }: ComboBoxProps<T>) {
113
+ export function ComboBox<T>({ menuAlign = "fill", menuGap, focusOnMount, onSelect, value, zIndex, unstyledInput, fullWidth, api, layout: layoutOpts, adapter, items, placeholder, clearable, noMatchMessage, openOnFocus }: ComboBoxProps<T>) {
108
114
  const [popupId] = useState(genComboboxPopupId());
109
115
  const popupCtrl = useRef<PopupController | undefined>(undefined);
110
116
  const inputRef = useRef<HTMLInputElement>(null);
@@ -143,11 +149,11 @@ export function ComboBox<T>({ menuAlign = "fill", menuGap, focusOnMount, onSelec
143
149
  }
144
150
  }, [api, ctrl, inputRef.current]);
145
151
 
146
- const showMenu = ctrl.isMenuOpen && ctrl.filteredItems.length > 0;
152
+ const showMenu = ctrl.isMenuOpen && (ctrl.filteredItems.length > 0 || !!noMatchMessage);
147
153
 
148
154
  return (
149
155
  <>
150
- <layout.Input boxRef={inputBoxRef} inputRef={inputRef} ctrl={ctrl} layout={layout} placeholder={placeholder} />
156
+ <layout.Input boxRef={inputBoxRef} inputRef={inputRef} ctrl={ctrl} layout={layout} placeholder={placeholder} clearable={clearable} openOnFocus={openOnFocus} />
151
157
  <Popup
152
158
  id={popupId}
153
159
  ctrlRef={popupCtrl}
@@ -159,7 +165,7 @@ export function ComboBox<T>({ menuAlign = "fill", menuGap, focusOnMount, onSelec
159
165
  align: menuAlign,
160
166
  gap: menuGap != null ? menuGap : 4
161
167
  }}>
162
- <layout.Menu fillWidth={menuAlign === "fill"} items={ctrl.filteredItems} ctrl={ctrl} layout={layout} adapter={adapter} />
168
+ <layout.Menu fillWidth={menuAlign === "fill"} items={ctrl.filteredItems} ctrl={ctrl} layout={layout} adapter={adapter} noMatchMessage={noMatchMessage} />
163
169
  </Popup>
164
170
  </>
165
171
  );
@@ -171,29 +177,42 @@ export interface ComboInputProps<T> {
171
177
  placeholder?: string
172
178
  boxRef?: React.RefObject<HTMLDivElement | null>;
173
179
  inputRef?: React.RefObject<HTMLInputElement | null>;
180
+ clearable?: boolean;
181
+ openOnFocus?: boolean;
174
182
  }
175
- function ComboInput<T>({ inputRef, placeholder, boxRef, ctrl, layout }: ComboInputProps<T>) {
176
- const buttonWidth = layout.buttonWidth;
177
- const style = buttonWidth > 0 ? { paddingRight: `${buttonWidth}px` } : undefined;
183
+ function ComboInput<T>({ inputRef, placeholder, boxRef, ctrl, layout, clearable, openOnFocus }: ComboInputProps<T>) {
178
184
  const Toggle = layout.Toggle;
185
+ const showClear = clearable && ctrl.selectedItem != null;
186
+ const buttonCount = (Toggle ? 1 : 0) + (showClear ? 1 : 0);
187
+ const style = buttonCount > 0 ? { paddingRight: `${layout.buttonWidth * buttonCount + layout.buttonRight}px` } : undefined;
179
188
  return (
180
189
  <div className="relative" ref={boxRef}>
181
- <input ref={inputRef} placeholder={placeholder} {...ctrl.getInputProps()} style={style} className={layout.inputClass} />
182
- {Toggle &&
183
- <button style={{
184
- top: 0, bottom: 0, right: `${layout.buttonRight}px`, width: `${buttonWidth}px`,
185
- position: "absolute",
186
- border: "none",
187
- padding: 0,
188
- margin: 0,
189
- backgroundColor: "transparent",
190
- display: "flex",
191
- alignItems: "center",
192
- justifyContent: "center"
193
- }} {...ctrl.getToggleButtonProps()}>
194
- <Toggle ctrl={ctrl} layout={layout} />
195
- </button>
196
- }
190
+ <input
191
+ ref={inputRef}
192
+ placeholder={placeholder}
193
+ {...ctrl.getInputProps()}
194
+ onFocus={openOnFocus ? () => ctrl.openMenu() : undefined}
195
+ style={style}
196
+ className={layout.inputClass}
197
+ />
198
+ <div style={{ position: 'absolute', right: `${layout.buttonRight}px`, top: 0, bottom: 0, display: 'flex', alignItems: 'center', gap: '2px' }}>
199
+ {showClear && (
200
+ <button
201
+ style={{ border: 'none', padding: 0, margin: 0, backgroundColor: 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', width: `${layout.buttonWidth}px` }}
202
+ onClick={() => { ctrl.selectedItem = null; }}
203
+ >
204
+ <XIcon className="w-4 h-4" />
205
+ </button>
206
+ )}
207
+ {Toggle && (
208
+ <button
209
+ style={{ width: `${layout.buttonWidth}px`, border: 'none', padding: 0, margin: 0, backgroundColor: 'transparent', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
210
+ {...ctrl.getToggleButtonProps()}
211
+ >
212
+ <Toggle ctrl={ctrl} layout={layout} />
213
+ </button>
214
+ )}
215
+ </div>
197
216
  </div>
198
217
  )
199
218
  }
@@ -212,9 +231,15 @@ export interface ComboMenuProps<T> {
212
231
  ctrl: ComboboxController<T>;
213
232
  adapter: OptionAdapter<T>;
214
233
  fillWidth: boolean;
234
+ noMatchMessage?: ReactNode;
215
235
  }
216
- function ComboMenu<T>({ fillWidth, items, layout, ctrl, adapter }: ComboMenuProps<T>) {
236
+ function ComboMenu<T>({ fillWidth, items, layout, ctrl, adapter, noMatchMessage }: ComboMenuProps<T>) {
217
237
  const { highlightedIndex, selectedItem } = ctrl;
238
+ if (items.length === 0) {
239
+ return noMatchMessage
240
+ ? <div style={{ width: fillWidth ? '100%' : undefined }} className={layout.menuClass}>{noMatchMessage}</div>
241
+ : null;
242
+ }
218
243
  return (
219
244
  <ul style={{ width: fillWidth ? "100%" : undefined, maxHeight: layout.maxMenuHeight ? `${layout.maxMenuHeight}px` : '240px' }}
220
245
  className={layout.menuClass} {...ctrl.getMenuProps()}>
@@ -485,4 +510,16 @@ function incrModulo(value: number, max: number) {
485
510
  }
486
511
  function decrModulo(value: number, max: number) {
487
512
  return (value - 1 + max) % max;
513
+ }
514
+
515
+ export function SimpleCombobox({
516
+ options,
517
+ creatable,
518
+ ...rest
519
+ }: Omit<ComboBoxProps<string>, 'adapter' | 'items'> & {
520
+ options: string[];
521
+ creatable?: boolean;
522
+ }) {
523
+ const adapter = creatable ? StringOptionAdapterWithCreate.instance : StringOptionAdapter.instance;
524
+ return <ComboBox adapter={adapter} items={options} {...rest} />;
488
525
  }
@@ -7,17 +7,20 @@ import { Info } from 'lucide-react';
7
7
  interface FormItemProps {
8
8
  label: any;
9
9
  children: ReactNode;
10
+ childrenId?: string;
10
11
  className?: string;
11
12
  description?: ReactNode;
12
13
  required?: boolean;
13
- direction?: "row" | "column";
14
+ direction?: "row" | "column" | "row-reverse";
14
15
  disabled?: boolean;
16
+ /** When true, the label row stretches to full width. Useful when placing actions (e.g. buttons) inside the label. */
17
+ fullWidthLabel?: boolean;
15
18
  }
16
- export function FormItem({ description, required, label, className, direction = "column", children, disabled = false }: FormItemProps) {
19
+ export function FormItem({ description, required, label, className, direction = "column", children, disabled = false, fullWidthLabel = false, childrenId }: FormItemProps) {
17
20
  return (
18
- <div className={clsx("flex w-full space-y-1", className, direction === "row" ? "flex-row justify-between items-center gap-2" : "flex-col")}>
19
- <div className='flex items-center gap-1'>
20
- <label className={`text-sm font-medium mb-1 ${disabled ? "text-muted" : ""}`}>
21
+ <div className={clsx("flex w-full space-y-1", className, direction === "row" ? "flex-row justify-between items-center gap-2" : direction === "row-reverse" ? "flex-row-reverse justify-between items-center gap-2" : "flex-col")}>
22
+ <div className={clsx('flex items-center gap-1 mb-0', fullWidthLabel && 'w-full')}>
23
+ <label htmlFor={childrenId} className={`text-sm font-medium mb-1 ${disabled ? "text-muted" : ""} ${fullWidthLabel && "flex-1"}`}>
21
24
  {label}{required ? <span className='text-destructive -mt-4 ml-1'>*</span> : ""}
22
25
  </label>
23
26
  {
@@ -33,4 +36,4 @@ export function FormItem({ description, required, label, className, direction =
33
36
  {children}
34
37
  </div>
35
38
  );
36
- }
39
+ }
@@ -86,7 +86,7 @@ export function SidePanel({ isOpen, title, onClose, children, panelWidth = 768,
86
86
  <Minus className="rotate-90 font-semibold" strokeWidth={4} />
87
87
  </div>
88
88
  )}
89
- <div className={`flex-1 flex flex-col bg-background shadow-xl ${className}`}>
89
+ <div className={`flex-1 min-w-0 flex flex-col bg-background shadow-xl ${className}`}>
90
90
  {/* Sticky header */}
91
91
  {title && (
92
92
  <div className="sticky top-0 z-10 bg-background px-2 sm:px-4 py-2 border-b">
@@ -102,8 +102,10 @@ export function SidePanel({ isOpen, title, onClose, children, panelWidth = 768,
102
102
  )}
103
103
 
104
104
  {/* Scrollable content */}
105
- <div className={contentClassName ?? "flex-1 overflow-y-auto px-2 sm:px-4 py-4"}>
106
- {children}
105
+ <div className={contentClassName ?? "flex-1 overflow-auto px-2 sm:px-4 py-4"}>
106
+ <div className='w-full h-full flex-1 flex flex-col'>
107
+ {children}
108
+ </div>
107
109
  </div>
108
110
  </div>
109
111
  </div>
@@ -1,6 +1,4 @@
1
- "use client"
2
-
3
- import { Collapsible as CollapsiblePrimitive } from "radix-ui"
1
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
4
2
 
5
3
  function Collapsible({
6
4
  ...props
@@ -10,9 +8,9 @@ function Collapsible({
10
8
 
11
9
  function CollapsibleTrigger({
12
10
  ...props
13
- }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
11
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Trigger>) {
14
12
  return (
15
- <CollapsiblePrimitive.CollapsibleTrigger
13
+ <CollapsiblePrimitive.Trigger
16
14
  data-slot="collapsible-trigger"
17
15
  {...props}
18
16
  />
@@ -21,9 +19,9 @@ function CollapsibleTrigger({
21
19
 
22
20
  function CollapsibleContent({
23
21
  ...props
24
- }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
22
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Content>) {
25
23
  return (
26
- <CollapsiblePrimitive.CollapsibleContent
24
+ <CollapsiblePrimitive.Content
27
25
  data-slot="collapsible-content"
28
26
  {...props}
29
27
  />
@@ -1,12 +1,12 @@
1
- "use client"
2
-
3
1
  import * as React from "react"
4
- import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
5
3
 
6
4
  import { cn } from "../libs/utils"
7
5
 
8
6
  import { CheckIcon, ChevronRightIcon } from "lucide-react"
9
7
 
8
+ const HoverMenuContext = React.createContext(false);
9
+
10
10
  function DropdownMenu({
11
11
  ...props
12
12
  }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
@@ -74,7 +74,7 @@ function DropdownMenuItem({
74
74
  data-inset={inset}
75
75
  data-variant={variant}
76
76
  className={cn(
77
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
77
+ "hover:bg-muted focus:bg-muted data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive gap-2 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
78
78
  className
79
79
  )}
80
80
  {...props}
@@ -96,7 +96,7 @@ function DropdownMenuCheckboxItem({
96
96
  data-slot="dropdown-menu-checkbox-item"
97
97
  data-inset={inset}
98
98
  className={cn(
99
- "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
99
+ "focus:bg-muted focus:text-muted focus:**:text-muted gap-2 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
100
100
  className
101
101
  )}
102
102
  checked={checked}
@@ -140,7 +140,7 @@ function DropdownMenuRadioItem({
140
140
  data-slot="dropdown-menu-radio-item"
141
141
  data-inset={inset}
142
142
  className={cn(
143
- "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
143
+ "focus:bg-muted focus:text-muted focus:**:text-muted gap-2 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
144
144
  className
145
145
  )}
146
146
  {...props}
@@ -170,7 +170,7 @@ function DropdownMenuLabel({
170
170
  <DropdownMenuPrimitive.Label
171
171
  data-slot="dropdown-menu-label"
172
172
  data-inset={inset}
173
- className={cn("text-muted-foreground px-1.5 py-1 text-xs font-medium data-inset:pl-7", className)}
173
+ className={cn("text-muted px-1.5 py-1 text-xs font-medium data-inset:pl-7", className)}
174
174
  {...props}
175
175
  />
176
176
  )
@@ -196,7 +196,7 @@ function DropdownMenuShortcut({
196
196
  return (
197
197
  <span
198
198
  data-slot="dropdown-menu-shortcut"
199
- className={cn("text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest", className)}
199
+ className={cn("text-muted group-focus/dropdown-menu-item:text-muted ml-auto text-xs tracking-widest", className)}
200
200
  {...props}
201
201
  />
202
202
  )
@@ -221,7 +221,7 @@ function DropdownMenuSubTrigger({
221
221
  data-slot="dropdown-menu-sub-trigger"
222
222
  data-inset={inset}
223
223
  className={cn(
224
- "focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0",
224
+ "focus:bg-muted focus:text-muted data-open:bg-muted data-open:text-muted not-data-[variant=destructive]:focus:**:text-muted gap-2 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0",
225
225
  className
226
226
  )}
227
227
  {...props}
@@ -271,8 +271,35 @@ interface DropdownProps {
271
271
  trigger: React.ReactNode;
272
272
  children: React.ReactNode | React.ReactNode[];
273
273
  align?: 'left' | 'center' | 'right';
274
+ hover?: boolean;
274
275
  }
275
- export function Dropdown({ trigger, children, align = 'right' }: DropdownProps) {
276
+ export function Dropdown({ trigger, children, align = 'right', hover }: DropdownProps) {
277
+ const [open, setOpen] = React.useState(false);
278
+ const closeTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null);
279
+
280
+ if (hover) {
281
+ const onEnter = () => {
282
+ if (closeTimer.current) clearTimeout(closeTimer.current);
283
+ setOpen(true);
284
+ };
285
+ const onLeave = () => {
286
+ closeTimer.current = setTimeout(() => setOpen(false), 80);
287
+ };
288
+ const alignClass = align === 'right' ? 'right-0' : align === 'center' ? 'left-1/2 -translate-x-1/2' : 'left-0';
289
+ return (
290
+ <div className="relative inline-flex" onMouseEnter={onEnter} onMouseLeave={onLeave}>
291
+ {trigger}
292
+ {open && (
293
+ <div className={cn('absolute top-full pt-1 z-50', alignClass)}>
294
+ <div className="min-w-32 rounded-lg p-1 shadow-md ring-1 ring-foreground/10 bg-popover text-popover-foreground">
295
+ <HoverMenuContext.Provider value={true}>{children}</HoverMenuContext.Provider>
296
+ </div>
297
+ </div>
298
+ )}
299
+ </div>
300
+ );
301
+ }
302
+
276
303
  return (
277
304
  <DropdownMenu>
278
305
  <DropdownMenuTrigger asChild>
@@ -287,19 +314,47 @@ export function Dropdown({ trigger, children, align = 'right' }: DropdownProps)
287
314
  );
288
315
  }
289
316
 
317
+ interface MenuGroupProps {
318
+ children: React.ReactNode | React.ReactNode[];
319
+ label?: string;
320
+ }
321
+ export function MenuGroup({ children, label }: MenuGroupProps) {
322
+ return (
323
+ <DropdownMenuGroup>
324
+ {label && <DropdownMenuLabel>{label}</DropdownMenuLabel>}
325
+ {children}
326
+ </DropdownMenuGroup>
327
+ );
328
+ }
329
+
290
330
  interface MenuItemProps {
291
331
  children: React.ReactNode | React.ReactNode[];
292
332
  onClick?: (ev: React.MouseEvent) => void;
293
333
  href?: string;
294
334
  closeOnClick?: boolean;
295
335
  isDisabled?: boolean;
336
+ variant?: "default" | "destructive";
337
+ className?: string;
296
338
  }
297
- export function MenuItem({ children, href, onClick, closeOnClick = true, isDisabled = false }: MenuItemProps) {
339
+ export function MenuItem({ children, href, onClick, isDisabled = false, variant = "default", className }: MenuItemProps) {
340
+ const isHoverMenu = React.useContext(HoverMenuContext);
341
+ const baseClass = cn(
342
+ "w-full gap-2 rounded-md px-1.5 py-1 text-sm text-nowrap [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center select-none [&_svg]:pointer-events-none [&_svg]:shrink-0",
343
+ variant === 'destructive' ? 'text-destructive' : '',
344
+ isDisabled ? 'pointer-events-none opacity-50' : 'hover:bg-muted focus:bg-muted',
345
+ className
346
+ );
347
+ if (isHoverMenu) {
348
+ const handleClick = (e: React.MouseEvent) => { e.stopPropagation(); onClick?.(e); };
349
+ return href
350
+ ? <a href={href} className={baseClass}>{children}</a>
351
+ : <button className={baseClass} disabled={isDisabled} onClick={handleClick}>{children}</button>;
352
+ }
298
353
  return (
299
354
  <DropdownMenuItem
300
- className="hover:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-nowrap"
355
+ className={cn("data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-nowrap", className)}
301
356
  disabled={isDisabled}
302
- onSelect={(e) => { if (!closeOnClick) e.preventDefault(); }}
357
+ variant={variant}
303
358
  onClick={(e) => { e.stopPropagation(); onClick?.(e); }}
304
359
  asChild={!!href}
305
360
  >
@@ -19,21 +19,21 @@ export const DateCombobox = ({
19
19
  const [localDateRange, setLocalDateRange] = useState<[Date | null, Date | null]>([null, null]);
20
20
  const { t } = useUITranslation();
21
21
 
22
- // For single date
23
- const selectedDate = filterValues[0] ? new Date(filterValues[0]) : undefined;
22
+ // Parse with dayjs to interpret bare YYYY-MM-DD as local time (to match UI).
23
+ const selectedDate = filterValues[0] ? dayjs(filterValues[0]).toDate() : undefined;
24
24
 
25
25
  // For date range - use local state for immediate feedback, fall back to filter values
26
26
  const dateRange: [Date | null, Date | null] = isRange ? [
27
- localDateRange[0] || (filterValues[0] ? new Date(filterValues[0]) : null),
28
- localDateRange[1] || (filterValues[1] ? new Date(filterValues[1]) : null)
27
+ localDateRange[0] || (filterValues[0] ? dayjs(filterValues[0]).toDate() : null),
28
+ localDateRange[1] || (filterValues[1] ? dayjs(filterValues[1]).toDate() : null)
29
29
  ] : [null, null];
30
30
 
31
31
  // Update local state when filter values change
32
32
  useEffect(() => {
33
33
  if (isRange) {
34
34
  setLocalDateRange([
35
- filterValues[0] ? new Date(filterValues[0]) : null,
36
- filterValues[1] ? new Date(filterValues[1]) : null
35
+ filterValues[0] ? dayjs(filterValues[0]).toDate() : null,
36
+ filterValues[1] ? dayjs(filterValues[1]).toDate() : null
37
37
  ]);
38
38
  }
39
39
  }, [filterValues, isRange]);
@@ -13,12 +13,14 @@ export const SelectionCombobox = ({
13
13
  setFilterValues,
14
14
  options,
15
15
  labelRenderer,
16
+ multiple = true,
16
17
  }: {
17
18
  filterType: string;
18
19
  filterValues: FilterOption[];
19
20
  setFilterValues: (filterValues: FilterOption[]) => void;
20
21
  options: FilterGroupOption[];
21
22
  labelRenderer?: (value: string) => React.ReactNode | Promise<React.ReactNode>;
23
+ multiple?: boolean;
22
24
  }) => {
23
25
  const [open, setOpen] = useState(false);
24
26
  const [commandInput, setCommandInput] = useState("");
@@ -88,7 +90,9 @@ export const SelectionCombobox = ({
88
90
  setOpen(false);
89
91
  }}
90
92
  >
91
- <input type="checkbox" checked={true} onChange={() => {}} />
93
+ {multiple && (
94
+ <input type="checkbox" checked={true} onChange={() => {}} />
95
+ )}
92
96
  <DynamicLabel
93
97
  value={value.value || ''}
94
98
  labelRenderer={labelRenderer}
@@ -112,20 +116,23 @@ export const SelectionCombobox = ({
112
116
  key={filter.value}
113
117
  value={String(filter.label || filter.value)}
114
118
  onSelect={() => {
115
- setFilterValues([...filterValues, {
119
+ const next = {
116
120
  value: filter.value,
117
121
  label: filter.label
118
- }]);
122
+ };
123
+ setFilterValues(multiple ? [...filterValues, next] : [next]);
119
124
  setTimeout(() => {
120
125
  setCommandInput("");
121
126
  }, 200);
122
127
  setOpen(false);
123
128
  }}
124
129
  >
125
- <Checkbox
126
- checked={false}
127
- className="opacity-0 group-data-[selected=true]:opacity-100"
128
- />
130
+ {multiple && (
131
+ <Checkbox
132
+ checked={false}
133
+ className="opacity-0 group-data-[selected=true]:opacity-100"
134
+ />
135
+ )}
129
136
  <span className="text-muted">
130
137
  <DynamicLabel
131
138
  value={filter.value || ''}
@@ -25,6 +25,7 @@ interface FilterProviderProps {
25
25
  setFilters: Dispatch<SetStateAction<Filter[]>>;
26
26
  filterGroups: FilterGroup[];
27
27
  children: React.ReactNode;
28
+ inModal?: boolean;
28
29
  }
29
30
 
30
31
  // Syncs filters ↔ URL. On mount, captures the initial URL param and restores matching filters
@@ -33,14 +34,15 @@ interface FilterProviderProps {
33
34
  // (prevents cross-page URL contamination, e.g. a modal inheriting a parent page's filters).
34
35
 
35
36
  // Parse format with array indicators: filterName:value or filterName:[value1,value2]
36
- const FilterProvider = ({ filters, setFilters, filterGroups, children }: FilterProviderProps) => {
37
+ const FilterProvider = ({ filters, setFilters, filterGroups, children, inModal }: FilterProviderProps) => {
37
38
  const url = new URL(window.location.href);
38
39
  const searchParams = url.searchParams;
39
40
  const [initialFiltersParam] = React.useState(() => new URLSearchParams(window.location.search).get('filters'));
40
41
  const processedUrlFilters = React.useRef<Set<string>>(new Set());
41
- const hasRestoredFromUrl = React.useRef(!initialFiltersParam);
42
+ const hasRestoredFromUrl = React.useRef(inModal || !initialFiltersParam);
42
43
 
43
44
  useEffect(() => {
45
+ if (inModal) return;
44
46
  if (!hasRestoredFromUrl.current) return;
45
47
  try {
46
48
  const params = new URLSearchParams(searchParams.toString());
@@ -82,7 +84,7 @@ const FilterProvider = ({ filters, setFilters, filterGroups, children }: FilterP
82
84
  }, [filters]);
83
85
 
84
86
  useEffect(() => {
85
- if (!initialFiltersParam || filterGroups.length === 0) return;
87
+ if (inModal || !initialFiltersParam || filterGroups.length === 0) return;
86
88
  try {
87
89
  const filterPairs = initialFiltersParam.split(';');
88
90
  const newFilters: Filter[] = [];
@@ -97,6 +97,7 @@ function generateComboboxOptions(
97
97
  }}
98
98
  options={filterGroup?.options || []}
99
99
  labelRenderer={filterGroup?.labelRenderer}
100
+ multiple={filter.multiple ?? filterGroup?.multiple}
100
101
  />
101
102
  );
102
103
  }