@alepha/ui 0.18.2 → 0.19.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 (257) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Bt1PjO6o.js} +3 -4
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Bt1PjO6o.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-C7c1CN4c.js} +3 -4
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-C7c1CN4c.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-C3RXpTp6.js} +3 -4
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-C3RXpTp6.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-31ivR6Wq.js} +3 -4
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-31ivR6Wq.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BABLe7hL.js} +73 -25
  10. package/dist/admin/AdminJobDashboard-BABLe7hL.js.map +1 -0
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D-G8RIlr.js} +3 -4
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D-G8RIlr.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-oIS3K9NX.js} +3 -4
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-oIS3K9NX.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-BmZ9mtXh.js} +8 -25
  16. package/dist/admin/AdminLayout-BmZ9mtXh.js.map +1 -0
  17. package/dist/admin/AdminNotifications-DHdzksww.js +541 -0
  18. package/dist/admin/AdminNotifications-DHdzksww.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CyZQSXnN.js} +118 -112
  20. package/dist/admin/AdminParameters-CyZQSXnN.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions--xwELDSO.js} +3 -4
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions--xwELDSO.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-DvBTG5gd.js} +82 -115
  24. package/dist/admin/AdminUserLayout-DvBTG5gd.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-CzsPBl6Z.js} +7 -6
  26. package/dist/admin/AdminUserProfile-CzsPBl6Z.js.map +1 -0
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-C-aUnhVN.js} +3 -4
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-C-aUnhVN.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-BYwei5sj.js} +4 -4
  30. package/dist/admin/AdminUsers-BYwei5sj.js.map +1 -0
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-CkPGLJku.js} +3 -4
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-CkPGLJku.js.map} +1 -1
  33. package/dist/{demo/IconGoogle-CSQLPYwX.js → admin/IconGoogle-8Nkx6yax.js} +2 -4
  34. package/dist/admin/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
  35. package/dist/admin/Login-DSBqNsZc.js +274 -0
  36. package/dist/admin/Login-DSBqNsZc.js.map +1 -0
  37. package/dist/admin/{Profile-B2EcIDB9.js → Profile-CDRjJo0P.js} +31 -29
  38. package/dist/admin/Profile-CDRjJo0P.js.map +1 -0
  39. package/dist/admin/{Register-Z3fxRbUF.js → Register-4QGFOnfh.js} +201 -146
  40. package/dist/admin/Register-4QGFOnfh.js.map +1 -0
  41. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-Gxc9L_mY.js} +9 -10
  42. package/dist/admin/ResetPassword-Gxc9L_mY.js.map +1 -0
  43. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-D7G5NnaN.js} +25 -11
  44. package/dist/admin/VerifyEmail-D7G5NnaN.js.map +1 -0
  45. package/dist/admin/adminUserAtom-DCi4wf-v.js +11 -0
  46. package/dist/admin/adminUserAtom-DCi4wf-v.js.map +1 -0
  47. package/dist/admin/{core-BVO_TQxb.js → core-D1AbU50V.js} +662 -570
  48. package/dist/admin/core-D1AbU50V.js.map +1 -0
  49. package/dist/admin/index.d.ts +141 -53
  50. package/dist/admin/index.d.ts.map +1 -1
  51. package/dist/admin/index.js +67 -49
  52. package/dist/admin/index.js.map +1 -1
  53. package/dist/admin/rolldown-runtime-CiIaOW0V.js +13 -0
  54. package/dist/{demo/AuthLayout-DN-ClJQk.js → auth/AuthLayout-CfRKcTqP.js} +3 -4
  55. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-CfRKcTqP.js.map} +1 -1
  56. package/dist/{admin/IconGoogle-Ch1m3Uzl.js → auth/IconGoogle-8Nkx6yax.js} +2 -4
  57. package/dist/auth/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
  58. package/dist/auth/Login-DJyweoPS.js +274 -0
  59. package/dist/auth/Login-DJyweoPS.js.map +1 -0
  60. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-Cy93pNTw.js} +31 -29
  61. package/dist/auth/Profile-Cy93pNTw.js.map +1 -0
  62. package/dist/auth/{Register-2gx8qll-.js → Register-CSqzzitW.js} +201 -146
  63. package/dist/auth/Register-CSqzzitW.js.map +1 -0
  64. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-B61QPlQi.js} +9 -10
  65. package/dist/auth/ResetPassword-B61QPlQi.js.map +1 -0
  66. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-CqBJ11id.js} +25 -11
  67. package/dist/auth/VerifyEmail-CqBJ11id.js.map +1 -0
  68. package/dist/auth/{core-DyfeVr5c.js → core-C6D3pazL.js} +403 -343
  69. package/dist/auth/core-C6D3pazL.js.map +1 -0
  70. package/dist/auth/index.d.ts +93 -54
  71. package/dist/auth/index.d.ts.map +1 -1
  72. package/dist/auth/index.js +30 -31
  73. package/dist/auth/index.js.map +1 -1
  74. package/dist/auth/rolldown-runtime-CiIaOW0V.js +13 -0
  75. package/dist/core/index.d.ts +123 -62
  76. package/dist/core/index.d.ts.map +1 -1
  77. package/dist/core/index.js +878 -776
  78. package/dist/core/index.js.map +1 -1
  79. package/dist/{auth/AuthLayout-C161NeF6.js → demo/AuthLayout-Dq5tSLSc.js} +3 -4
  80. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Dq5tSLSc.js.map} +1 -1
  81. package/dist/demo/DemoButton-_Ws2w-J0.js +181 -0
  82. package/dist/demo/DemoButton-_Ws2w-J0.js.map +1 -0
  83. package/dist/demo/DemoControlSelect-ChP4ZOpQ.js +304 -0
  84. package/dist/demo/DemoControlSelect-ChP4ZOpQ.js.map +1 -0
  85. package/dist/demo/DemoDataTable-Hwf_UUni.js +361 -0
  86. package/dist/demo/DemoDataTable-Hwf_UUni.js.map +1 -0
  87. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-B01OMVRd.js} +3 -4
  88. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-B01OMVRd.js.map} +1 -1
  89. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-870PEl0V.js} +4 -5
  90. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-870PEl0V.js.map} +1 -1
  91. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C1YR27fz.js} +4 -5
  92. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C1YR27fz.js.map} +1 -1
  93. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-DRbL2eGf.js} +4 -5
  94. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-DRbL2eGf.js.map} +1 -1
  95. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-DoABiqBW.js} +4 -5
  96. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-DoABiqBW.js.map} +1 -1
  97. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CN_PDCX2.js} +16 -8
  98. package/dist/demo/DemoLayout-CN_PDCX2.js.map +1 -0
  99. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-B5x-ug3Q.js} +51 -35
  100. package/dist/demo/DemoLogin-B5x-ug3Q.js.map +1 -0
  101. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-Q6sg2xuV.js} +51 -53
  102. package/dist/demo/DemoRegister-Q6sg2xuV.js.map +1 -0
  103. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-DrqZfmEw.js} +14 -19
  104. package/dist/demo/DemoResetPassword-DrqZfmEw.js.map +1 -0
  105. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-CfKS6w1o.js} +4 -5
  106. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-CfKS6w1o.js.map} +1 -1
  107. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-pT6Gi5b5.js} +4 -5
  108. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-pT6Gi5b5.js.map} +1 -1
  109. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-I13NBzQQ.js} +3 -4
  110. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-I13NBzQQ.js.map} +1 -1
  111. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-BqzcrtvN.js} +9 -6
  112. package/dist/demo/DemoTypeForm-BqzcrtvN.js.map +1 -0
  113. package/dist/demo/DemoVerifyEmail-HwD8xfQw.js +33 -0
  114. package/dist/demo/DemoVerifyEmail-HwD8xfQw.js.map +1 -0
  115. package/dist/{auth/IconGoogle-Ch1m3Uzl.js → demo/IconGoogle-CwQy4G9y.js} +2 -4
  116. package/dist/demo/{IconGoogle-CSQLPYwX.js.map → IconGoogle-CwQy4G9y.js.map} +1 -1
  117. package/dist/demo/Login-CqG1iJbn.js +274 -0
  118. package/dist/demo/Login-CqG1iJbn.js.map +1 -0
  119. package/dist/demo/{Profile-BE_Y3co2.js → Profile-C0ojJCaG.js} +31 -29
  120. package/dist/demo/Profile-C0ojJCaG.js.map +1 -0
  121. package/dist/demo/{Register-fXHmBpr3.js → Register-KKZwr_lL.js} +201 -146
  122. package/dist/demo/Register-KKZwr_lL.js.map +1 -0
  123. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-DMrLFEtr.js} +9 -10
  124. package/dist/demo/ResetPassword-DMrLFEtr.js.map +1 -0
  125. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D49Wud2v.js} +65 -68
  126. package/dist/demo/Showcase-D49Wud2v.js.map +1 -0
  127. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BFCAFz6T.js} +25 -11
  128. package/dist/demo/VerifyEmail-BFCAFz6T.js.map +1 -0
  129. package/dist/demo/{auth-Djd7SKiw.js → auth-D9qTZzCa.js} +18 -35
  130. package/dist/demo/{auth-Djd7SKiw.js.map → auth-D9qTZzCa.js.map} +1 -1
  131. package/dist/demo/{core-B7LNjM78.js → core-DRtQklr3.js} +752 -647
  132. package/dist/demo/core-DRtQklr3.js.map +1 -0
  133. package/dist/demo/index.d.ts +1 -0
  134. package/dist/demo/index.d.ts.map +1 -1
  135. package/dist/demo/index.js +25 -22
  136. package/dist/demo/index.js.map +1 -1
  137. package/dist/demo/rolldown-runtime-CiIaOW0V.js +13 -0
  138. package/package.json +19 -19
  139. package/src/admin/AdminRouter.tsx +42 -2
  140. package/src/admin/atoms/adminUserAtom.ts +7 -0
  141. package/src/admin/components/AdminLayout.tsx +2 -14
  142. package/src/admin/components/jobs/AdminJobDashboard.tsx +51 -20
  143. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  144. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  145. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  146. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  147. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  148. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  149. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  150. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  151. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  152. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  153. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  154. package/src/admin/components/users/AdminUserLayout.tsx +84 -127
  155. package/src/admin/components/users/AdminUserProfile.tsx +5 -2
  156. package/src/admin/components/users/AdminUsers.tsx +1 -1
  157. package/src/auth/components/Login.tsx +188 -121
  158. package/src/auth/components/Profile.tsx +1 -22
  159. package/src/auth/components/ProfileField.tsx +39 -0
  160. package/src/auth/components/Register.tsx +215 -158
  161. package/src/auth/components/ResetPassword.tsx +7 -11
  162. package/src/auth/components/VerifyEmail.tsx +35 -10
  163. package/src/auth/components/buttons/UserButton.tsx +19 -21
  164. package/src/auth/index.ts +1 -0
  165. package/src/core/components/Flex.tsx +34 -0
  166. package/src/core/components/buttons/ActionButton.tsx +105 -78
  167. package/src/core/components/data/DetailDrawer.tsx +102 -96
  168. package/src/core/components/data/DetailList.tsx +2 -1
  169. package/src/core/components/dialogs/PromptDialog.tsx +1 -1
  170. package/src/core/components/layout/Breadcrumb.tsx +4 -7
  171. package/src/core/components/layout/DashboardShell.tsx +18 -4
  172. package/src/core/components/layout/Sidebar.tsx +16 -241
  173. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  174. package/src/core/components/layout/SidebarItem.tsx +146 -0
  175. package/src/core/components/layout/index.ts +3 -1
  176. package/src/core/form/components/Control.tsx +31 -29
  177. package/src/core/form/components/ControlArray.tsx +13 -39
  178. package/src/core/form/components/ControlDate.tsx +10 -21
  179. package/src/core/form/components/ControlNumber.tsx +4 -33
  180. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  181. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  182. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  183. package/src/core/form/components/ControlSelect.tsx +294 -92
  184. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  185. package/src/core/form/components/TypeForm.tsx +5 -2
  186. package/src/core/form/index.ts +8 -1
  187. package/src/core/form/utils/parseInput.ts +7 -3
  188. package/src/core/index.ts +3 -1
  189. package/src/core/json/components/JsonViewer.tsx +103 -319
  190. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  191. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  192. package/src/core/json/components/JsonViewerShared.ts +76 -0
  193. package/src/core/services/DialogService.tsx +2 -2
  194. package/src/core/styles.css +13 -2
  195. package/src/core/table/components/ColumnPicker.tsx +3 -3
  196. package/src/core/table/components/DataTable.tsx +88 -29
  197. package/src/core/table/components/DataTableFilters.tsx +6 -11
  198. package/src/core/table/components/DataTablePagination.tsx +9 -3
  199. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  200. package/src/core/table/components/FilterPicker.tsx +3 -3
  201. package/src/core/table/interfaces/types.ts +29 -0
  202. package/src/core/utils/icons.tsx +2 -2
  203. package/src/demo/DemoRouter.ts +8 -1
  204. package/src/demo/components/DemoLayout.tsx +12 -2
  205. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  206. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  207. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  208. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  209. package/src/demo/components/core/DemoButton.tsx +123 -103
  210. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  211. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  212. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  213. package/src/demo/components/shared/MacWindow.tsx +5 -11
  214. package/src/demo/components/shared/Showcase.tsx +28 -42
  215. package/dist/admin/AdminJobDashboard-KIOkeMgE.js.map +0 -1
  216. package/dist/admin/AdminLayout-B1DXZHDn.js.map +0 -1
  217. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  218. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  219. package/dist/admin/AdminUserProfile-DuTUnjdG.js.map +0 -1
  220. package/dist/admin/AdminUsers-CR9z0g_5.js.map +0 -1
  221. package/dist/admin/Login-DHbYJKwg.js +0 -219
  222. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  223. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  224. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  225. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  226. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  227. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  228. package/dist/admin/rolldown-runtime-CjeV3_4I.js +0 -18
  229. package/dist/auth/Login-C7jIqf00.js +0 -219
  230. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  231. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  232. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  233. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  234. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  235. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  236. package/dist/auth/rolldown-runtime-CjeV3_4I.js +0 -18
  237. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  238. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  239. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  240. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  241. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  242. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  243. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  244. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  245. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  246. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  247. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  248. package/dist/demo/Login-CoYf_P_F.js +0 -219
  249. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  250. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  251. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  252. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  253. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  254. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  255. package/dist/demo/core-B7LNjM78.js.map +0 -1
  256. package/dist/demo/rolldown-runtime-CjeV3_4I.js +0 -18
  257. package/src/demo/styles.css +0 -0
@@ -0,0 +1,165 @@
1
+ import { ActionButton, OPERATOR_INFO, type SchemaField, ui } from "@alepha/ui";
2
+ import { Badge, Divider, Flex, Text } from "@mantine/core";
3
+
4
+ export interface ControlQueryBuilderHelpProps {
5
+ /**
6
+ * Schema fields to display
7
+ */
8
+ fields: SchemaField[];
9
+
10
+ /**
11
+ * Callback when a text snippet is inserted
12
+ */
13
+ onInsert: (text: string) => void;
14
+ }
15
+
16
+ const ControlQueryBuilderHelp = (props: ControlQueryBuilderHelpProps) => {
17
+ const { fields, onInsert } = props;
18
+
19
+ return (
20
+ <Flex
21
+ gap="md"
22
+ align="flex-start"
23
+ wrap="nowrap"
24
+ bg={ui.colors.surface}
25
+ p={"sm"}
26
+ bdrs={"sm"}
27
+ >
28
+ {/* Left Column: Operators */}
29
+ <Flex direction="column" gap="md" style={{ flex: 1 }}>
30
+ {/* Available Operators */}
31
+ <Flex direction="column" gap="xs">
32
+ <Text size="sm" fw={600}>
33
+ Operators
34
+ </Text>
35
+ <Flex direction="column" gap={4}>
36
+ {Object.entries(OPERATOR_INFO).map(([key, info]) => (
37
+ <Flex key={key} gap="xs" wrap="nowrap">
38
+ <ActionButton
39
+ px={"xs"}
40
+ size={"xs"}
41
+ h={24}
42
+ variant={"default"}
43
+ justify={"center"}
44
+ miw={48}
45
+ onClick={() => onInsert(info.symbol)}
46
+ >
47
+ {info.symbol}
48
+ </ActionButton>
49
+ <Text size="xs" c="dimmed" style={{ flex: 1 }}>
50
+ {info.label}
51
+ </Text>
52
+ </Flex>
53
+ ))}
54
+ </Flex>
55
+ </Flex>
56
+
57
+ <Divider />
58
+
59
+ {/* Logic Operators */}
60
+ <Flex direction="column" gap="xs">
61
+ <Text size="sm" fw={600}>
62
+ Logic
63
+ </Text>
64
+ <Flex direction="column" gap={4}>
65
+ <Flex gap="xs" wrap="nowrap">
66
+ <ActionButton
67
+ px={"xs"}
68
+ size={"xs"}
69
+ h={24}
70
+ variant={"default"}
71
+ justify={"center"}
72
+ miw={48}
73
+ onClick={() => onInsert("&")}
74
+ >
75
+ &
76
+ </ActionButton>
77
+ <Text size="xs" c="dimmed">
78
+ AND
79
+ </Text>
80
+ </Flex>
81
+ <Flex gap="xs" wrap="nowrap">
82
+ <ActionButton
83
+ px={"xs"}
84
+ size={"xs"}
85
+ h={24}
86
+ variant={"default"}
87
+ justify={"center"}
88
+ miw={48}
89
+ onClick={() => onInsert("|")}
90
+ >
91
+ |
92
+ </ActionButton>
93
+ <Text size="xs" c="dimmed">
94
+ OR
95
+ </Text>
96
+ </Flex>
97
+ </Flex>
98
+ </Flex>
99
+ </Flex>
100
+
101
+ {/* Divider */}
102
+ {fields.length > 0 && <Divider orientation="vertical" />}
103
+
104
+ {/* Right Column: Fields */}
105
+ {fields.length > 0 && (
106
+ <Flex direction={"column"} gap="xs" style={{ flex: 2 }}>
107
+ <Text size="sm" fw={600}>
108
+ Fields
109
+ </Text>
110
+ <Flex
111
+ direction={"column"}
112
+ gap={4}
113
+ style={{ maxHeight: 300, overflowY: "auto" }}
114
+ >
115
+ {fields.map((field) => (
116
+ <Flex key={field.path} gap="xs" wrap="nowrap" align="flex-start">
117
+ <ActionButton
118
+ px={"xs"}
119
+ size={"xs"}
120
+ h={24}
121
+ variant={"default"}
122
+ justify={"end"}
123
+ miw={120}
124
+ onClick={() => onInsert(field.path)}
125
+ >
126
+ {field.path}
127
+ </ActionButton>
128
+ <Flex
129
+ mt={3}
130
+ direction={"column"}
131
+ gap={2}
132
+ style={{ flex: 1, minWidth: 0 }}
133
+ >
134
+ <Text size="xs" c="dimmed" lineClamp={1}>
135
+ {field.description || field.type}
136
+ </Text>
137
+ {field.enum && (
138
+ <Flex gap={0} wrap="wrap">
139
+ {field.enum.map((enumValue) => (
140
+ <ActionButton
141
+ px={"xs"}
142
+ size={"xs"}
143
+ h={24}
144
+ key={enumValue}
145
+ onClick={() => onInsert(enumValue)}
146
+ >
147
+ {enumValue}
148
+ </ActionButton>
149
+ ))}
150
+ </Flex>
151
+ )}
152
+ </Flex>
153
+ <Badge size="xs" variant="light" style={{ flexShrink: 0 }}>
154
+ {field.type}
155
+ </Badge>
156
+ </Flex>
157
+ ))}
158
+ </Flex>
159
+ </Flex>
160
+ )}
161
+ </Flex>
162
+ );
163
+ };
164
+
165
+ export default ControlQueryBuilderHelp;
@@ -0,0 +1,343 @@
1
+ import { MantineProvider } from "@mantine/core";
2
+ import { fireEvent, screen, waitFor } from "@testing-library/react";
3
+ import { Alepha, t } from "alepha";
4
+ import { AlephaLogger } from "alepha/logger";
5
+ import { useForm } from "alepha/react/form";
6
+ import {
7
+ renderWithAlepha as renderWithAlephaUtil,
8
+ setupJsdomMocks,
9
+ } from "alepha/react/testing";
10
+ import { beforeAll, describe, it } from "vitest";
11
+ import TypeForm from "./TypeForm.tsx";
12
+
13
+ beforeAll(() => {
14
+ setupJsdomMocks();
15
+
16
+ // Mantine combobox calls scrollIntoView on options which is not available in jsdom
17
+ Element.prototype.scrollIntoView = () => {};
18
+ });
19
+
20
+ describe("ControlSelect", () => {
21
+ const renderWithAlepha = async (element: React.ReactElement) => {
22
+ const alepha = Alepha.create().with(AlephaLogger);
23
+ const result = await renderWithAlephaUtil(element, {
24
+ alepha,
25
+ wrapper: MantineProvider,
26
+ });
27
+ return { ...result, alepha };
28
+ };
29
+
30
+ describe("Select (single enum)", () => {
31
+ it("should render a select input for an enum field", async ({ expect }) => {
32
+ const Form = () => {
33
+ const form = useForm({
34
+ id: "select-test",
35
+ schema: t.object({
36
+ color: t.enum(["red", "green", "blue"]),
37
+ }),
38
+ handler: () => {},
39
+ });
40
+
41
+ return <TypeForm form={form} />;
42
+ };
43
+
44
+ await renderWithAlepha(<Form />);
45
+
46
+ const selectInput = screen.getByTestId("select-test-color");
47
+ expect(selectInput).toBeDefined();
48
+ expect(selectInput.getAttribute("aria-haspopup")).toBe("listbox");
49
+ });
50
+
51
+ it("should submit the selected value", async ({ expect }) => {
52
+ const calls: Array<any> = [];
53
+
54
+ const Form = () => {
55
+ const form = useForm({
56
+ id: "select-submit-test",
57
+ schema: t.object({
58
+ color: t.enum(["red", "green", "blue"]),
59
+ }),
60
+ handler: (values) => {
61
+ calls.push(values);
62
+ },
63
+ });
64
+
65
+ return <TypeForm form={form} />;
66
+ };
67
+
68
+ await renderWithAlepha(<Form />);
69
+
70
+ const selectInput = screen.getByTestId("select-submit-test-color");
71
+ fireEvent.click(selectInput);
72
+
73
+ // Mantine dropdown is rendered but hidden in jsdom — query options directly
74
+ const option = document.querySelector(
75
+ '[role="option"][value="red"]',
76
+ ) as HTMLElement;
77
+ expect(option).toBeDefined();
78
+ fireEvent.click(option);
79
+
80
+ fireEvent.submit(screen.getByText("Submit"));
81
+
82
+ await waitFor(() => expect(calls.length).toBe(1));
83
+ expect(calls[0]).toEqual({ color: "red" });
84
+ });
85
+ });
86
+
87
+ describe("MultiSelect (array of enums)", () => {
88
+ it("should render a multiselect for an array of enums", async ({
89
+ expect,
90
+ }) => {
91
+ const Form = () => {
92
+ const form = useForm({
93
+ id: "multi-test",
94
+ schema: t.object({
95
+ roles: t.array(t.enum(["admin", "editor", "viewer"])),
96
+ }),
97
+ handler: () => {},
98
+ });
99
+
100
+ return <TypeForm form={form} />;
101
+ };
102
+
103
+ await renderWithAlepha(<Form />);
104
+
105
+ expect(screen.getByText("Roles")).toBeDefined();
106
+
107
+ // MultiSelect does not propagate data-testid; verify via input id
108
+ const input = document.getElementById("multi-test-roles") as HTMLElement;
109
+ expect(input).toBeDefined();
110
+ expect(input.getAttribute("aria-haspopup")).toBe("listbox");
111
+ });
112
+ });
113
+
114
+ describe("Autocomplete (creatable + single)", () => {
115
+ it("should render an autocomplete when creatable is true", async ({
116
+ expect,
117
+ }) => {
118
+ const Form = () => {
119
+ const form = useForm({
120
+ id: "autocomplete-test",
121
+ schema: t.object({
122
+ fruit: t.enum(["apple", "banana", "cherry"]),
123
+ }),
124
+ handler: () => {},
125
+ });
126
+
127
+ return (
128
+ <TypeForm
129
+ form={form}
130
+ fieldControlProps={{
131
+ fruit: { select: { creatable: true } },
132
+ }}
133
+ />
134
+ );
135
+ };
136
+
137
+ await renderWithAlepha(<Form />);
138
+
139
+ // Autocomplete renders inside an Autocomplete-root wrapper
140
+ const root = document.querySelector(
141
+ ".mantine-Autocomplete-root",
142
+ ) as HTMLElement;
143
+ expect(root).toBeDefined();
144
+
145
+ // The input element has the id and role=combobox
146
+ const input = document.getElementById(
147
+ "autocomplete-test-fruit",
148
+ ) as HTMLElement;
149
+ expect(input).toBeDefined();
150
+ expect(input.tagName).toBe("INPUT");
151
+ });
152
+
153
+ it("should accept a typed freeform value", async ({ expect }) => {
154
+ const calls: Array<any> = [];
155
+
156
+ const Form = () => {
157
+ const form = useForm({
158
+ id: "autocomplete-freeform-test",
159
+ schema: t.object({
160
+ fruit: t.text(),
161
+ }),
162
+ handler: (values) => {
163
+ calls.push(values);
164
+ },
165
+ });
166
+
167
+ return (
168
+ <TypeForm
169
+ form={form}
170
+ fieldControlProps={{
171
+ fruit: {
172
+ select: {
173
+ creatable: true,
174
+ autocompleteProps: {
175
+ data: ["apple", "banana", "cherry"],
176
+ },
177
+ },
178
+ },
179
+ }}
180
+ />
181
+ );
182
+ };
183
+
184
+ await renderWithAlepha(<Form />);
185
+
186
+ const input = document.getElementById(
187
+ "autocomplete-freeform-test-fruit",
188
+ ) as HTMLInputElement;
189
+ expect(input).toBeDefined();
190
+
191
+ fireEvent.change(input, { target: { value: "mango" } });
192
+ fireEvent.submit(screen.getByText("Submit"));
193
+
194
+ await waitFor(() => expect(calls.length).toBe(1));
195
+ expect(calls[0]).toEqual({ fruit: "mango" });
196
+ });
197
+ });
198
+
199
+ describe("TagsInput (creatable + array)", () => {
200
+ it("should render tags input for creatable array of enums", async ({
201
+ expect,
202
+ }) => {
203
+ const Form = () => {
204
+ const form = useForm({
205
+ id: "tags-test",
206
+ schema: t.object({
207
+ skills: t.array(t.enum(["js", "ts", "python"])),
208
+ }),
209
+ handler: () => {},
210
+ });
211
+
212
+ return (
213
+ <TypeForm
214
+ form={form}
215
+ fieldControlProps={{
216
+ skills: { select: { creatable: true } },
217
+ }}
218
+ />
219
+ );
220
+ };
221
+
222
+ await renderWithAlepha(<Form />);
223
+
224
+ expect(screen.getByText("Skills")).toBeDefined();
225
+ });
226
+
227
+ it("should show default tag pills", async ({ expect }) => {
228
+ const Form = () => {
229
+ const form = useForm({
230
+ id: "tags-default-test",
231
+ schema: t.object({
232
+ skills: t.array(t.enum(["js", "ts", "python"]), {
233
+ default: ["js", "ts"],
234
+ }),
235
+ }),
236
+ handler: () => {},
237
+ });
238
+
239
+ return (
240
+ <TypeForm
241
+ form={form}
242
+ fieldControlProps={{
243
+ skills: { select: { creatable: true } },
244
+ }}
245
+ />
246
+ );
247
+ };
248
+
249
+ await renderWithAlepha(<Form />);
250
+
251
+ expect(screen.getByText("js")).toBeDefined();
252
+ expect(screen.getByText("ts")).toBeDefined();
253
+ });
254
+ });
255
+
256
+ describe("SegmentedControl", () => {
257
+ it("should render segmented control with enum data", async ({ expect }) => {
258
+ const Form = () => {
259
+ const form = useForm({
260
+ id: "segmented-test",
261
+ schema: t.object({
262
+ size: t.enum(["small", "medium", "large"]),
263
+ }),
264
+ handler: () => {},
265
+ });
266
+
267
+ return (
268
+ <TypeForm
269
+ form={form}
270
+ fieldControlProps={{
271
+ size: { segmented: true },
272
+ }}
273
+ skipSubmitButton
274
+ />
275
+ );
276
+ };
277
+
278
+ await renderWithAlepha(<Form />);
279
+
280
+ expect(screen.getByText("small")).toBeDefined();
281
+ expect(screen.getByText("medium")).toBeDefined();
282
+ expect(screen.getByText("large")).toBeDefined();
283
+ });
284
+ });
285
+
286
+ describe("Numeric coercion", () => {
287
+ it("should coerce select value to number for integer schema", async ({
288
+ expect,
289
+ }) => {
290
+ const calls: Array<any> = [];
291
+
292
+ const Form = () => {
293
+ const form = useForm({
294
+ id: "numeric-test",
295
+ schema: t.object({
296
+ priority: t.integer({ enum: [1, 2, 3] }),
297
+ }),
298
+ handler: (values) => {
299
+ calls.push(values);
300
+ },
301
+ });
302
+
303
+ return (
304
+ <TypeForm
305
+ form={form}
306
+ fieldControlProps={{
307
+ priority: {
308
+ select: {
309
+ selectProps: {
310
+ data: [
311
+ { value: "1", label: "Low" },
312
+ { value: "2", label: "Medium" },
313
+ { value: "3", label: "High" },
314
+ ],
315
+ },
316
+ },
317
+ },
318
+ }}
319
+ />
320
+ );
321
+ };
322
+
323
+ await renderWithAlepha(<Form />);
324
+
325
+ const selectInput = screen.getByTestId("numeric-test-priority");
326
+ expect(selectInput).toBeDefined();
327
+
328
+ fireEvent.click(selectInput);
329
+
330
+ // Query options directly since Mantine dropdown is hidden in jsdom
331
+ const option = document.querySelector(
332
+ '[role="option"][value="2"]',
333
+ ) as HTMLElement;
334
+ expect(option).toBeDefined();
335
+ fireEvent.click(option);
336
+
337
+ fireEvent.submit(screen.getByText("Submit"));
338
+
339
+ await waitFor(() => expect(calls.length).toBe(1));
340
+ expect(calls[0]).toEqual({ priority: 2 });
341
+ });
342
+ });
343
+ });