@alepha/ui 0.18.2 → 0.18.3

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 (231) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Dy_k-4Vd.js} +2 -2
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Dy_k-4Vd.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-CKiFMSSU.js} +2 -2
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-CKiFMSSU.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-PhC_dZqo.js} +2 -2
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-PhC_dZqo.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-DFTjijGp.js} +2 -2
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-DFTjijGp.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D9E-CS-U.js} +2 -2
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D9E-CS-U.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-Ci9ue1zC.js} +2 -2
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-Ci9ue1zC.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-I6TlUMPc.js} +2 -2
  16. package/dist/admin/{AdminLayout-B1DXZHDn.js.map → AdminLayout-I6TlUMPc.js.map} +1 -1
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions-Bz5NRuoW.js} +2 -2
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions-Bz5NRuoW.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DuTUnjdG.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-CT_YDim0.js} +2 -2
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-CT_YDim0.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-D1UfGya9.js} +2 -2
  30. package/dist/admin/{AdminUsers-CR9z0g_5.js.map → AdminUsers-D1UfGya9.js.map} +1 -1
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/Login-xtNmQtGh.js +275 -0
  34. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  35. package/dist/admin/{Profile-B2EcIDB9.js → Profile-_AtPUwAP.js} +31 -27
  36. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  37. package/dist/admin/{Register-Z3fxRbUF.js → Register-JcCjHUUn.js} +198 -142
  38. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  39. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-CwGBPLJO.js} +7 -7
  40. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  41. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-hNxWejWf.js} +23 -8
  42. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  43. package/dist/admin/{core-BVO_TQxb.js → core-CYaRQ8O-.js} +709 -556
  44. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  45. package/dist/admin/index.d.ts +83 -44
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +58 -39
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/auth/{AuthLayout-C161NeF6.js → AuthLayout-AvLlcLjS.js} +2 -2
  50. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  51. package/dist/auth/Login-BA1E8IZl.js +275 -0
  52. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  53. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-YcWdeuFz.js} +31 -27
  54. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  55. package/dist/auth/{Register-2gx8qll-.js → Register-CPhEO5MG.js} +198 -142
  56. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  57. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  58. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  59. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  60. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  61. package/dist/auth/{core-DyfeVr5c.js → core-D5jIAVF2.js} +386 -294
  62. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  63. package/dist/auth/index.d.ts +93 -48
  64. package/dist/auth/index.d.ts.map +1 -1
  65. package/dist/auth/index.js +28 -24
  66. package/dist/auth/index.js.map +1 -1
  67. package/dist/core/index.d.ts +116 -61
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +873 -701
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/demo/{AuthLayout-DN-ClJQk.js → AuthLayout-Brri4A-L.js} +2 -2
  72. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  73. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  74. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  75. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  76. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  77. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  78. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  79. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-CUWdLHim.js} +2 -2
  80. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  81. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-a8OhMMvq.js} +3 -3
  82. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  83. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C13OVDfS.js} +3 -3
  84. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  85. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-D_De3UiT.js} +2 -2
  86. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  87. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  88. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  89. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CHU8WTwO.js} +14 -5
  90. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  91. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-BBlrWpml.js} +49 -32
  92. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  93. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-BuNE3_-f.js} +49 -50
  94. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  95. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  96. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  97. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-Giy2HRBD.js} +3 -3
  98. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  99. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-ubcw-vog.js} +3 -3
  100. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-ubcw-vog.js.map} +1 -1
  101. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-9die_dYT.js} +2 -2
  102. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-9die_dYT.js.map} +1 -1
  103. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  104. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  105. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  106. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  107. package/dist/demo/Login-C12N4oGs.js +275 -0
  108. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  109. package/dist/demo/{Profile-BE_Y3co2.js → Profile-DS5q4vOh.js} +31 -27
  110. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  111. package/dist/demo/{Register-fXHmBpr3.js → Register-B4hLBeEv.js} +198 -142
  112. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  113. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  114. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  115. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D6Fxt4X4.js} +64 -65
  116. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  117. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  118. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  119. package/dist/demo/{auth-Djd7SKiw.js → auth-ByVTreDl.js} +8 -8
  120. package/dist/demo/{auth-Djd7SKiw.js.map → auth-ByVTreDl.js.map} +1 -1
  121. package/dist/demo/{core-B7LNjM78.js → core-DFgB3yU4.js} +741 -573
  122. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  123. package/dist/demo/index.d.ts +1 -0
  124. package/dist/demo/index.d.ts.map +1 -1
  125. package/dist/demo/index.js +24 -18
  126. package/dist/demo/index.js.map +1 -1
  127. package/package.json +7 -7
  128. package/src/admin/AdminRouter.tsx +24 -1
  129. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  130. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  131. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  132. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  133. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  134. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  135. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  136. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  137. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  138. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  139. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  140. package/src/auth/components/Login.tsx +188 -121
  141. package/src/auth/components/Profile.tsx +1 -22
  142. package/src/auth/components/ProfileField.tsx +39 -0
  143. package/src/auth/components/Register.tsx +215 -158
  144. package/src/auth/components/ResetPassword.tsx +7 -11
  145. package/src/auth/components/VerifyEmail.tsx +35 -10
  146. package/src/auth/components/buttons/UserButton.tsx +19 -21
  147. package/src/auth/index.ts +1 -0
  148. package/src/core/components/Flex.tsx +10 -0
  149. package/src/core/components/buttons/ActionButton.tsx +104 -78
  150. package/src/core/components/data/DetailDrawer.tsx +102 -96
  151. package/src/core/components/data/DetailList.tsx +2 -1
  152. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  153. package/src/core/components/layout/DashboardShell.tsx +18 -4
  154. package/src/core/components/layout/Sidebar.tsx +16 -241
  155. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  156. package/src/core/components/layout/SidebarItem.tsx +146 -0
  157. package/src/core/components/layout/index.ts +3 -1
  158. package/src/core/form/components/Control.tsx +31 -29
  159. package/src/core/form/components/ControlArray.tsx +13 -39
  160. package/src/core/form/components/ControlDate.tsx +10 -21
  161. package/src/core/form/components/ControlNumber.tsx +4 -33
  162. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  163. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  164. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  165. package/src/core/form/components/ControlSelect.tsx +294 -92
  166. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  167. package/src/core/form/components/TypeForm.tsx +5 -2
  168. package/src/core/form/index.ts +8 -1
  169. package/src/core/form/utils/parseInput.ts +7 -3
  170. package/src/core/index.ts +3 -1
  171. package/src/core/json/components/JsonViewer.tsx +103 -319
  172. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  173. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  174. package/src/core/json/components/JsonViewerShared.ts +76 -0
  175. package/src/core/styles.css +12 -2
  176. package/src/core/table/components/ColumnPicker.tsx +3 -3
  177. package/src/core/table/components/DataTable.tsx +89 -29
  178. package/src/core/table/components/DataTableFilters.tsx +6 -11
  179. package/src/core/table/components/DataTablePagination.tsx +9 -3
  180. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  181. package/src/core/table/components/FilterPicker.tsx +3 -3
  182. package/src/core/table/interfaces/types.ts +29 -0
  183. package/src/core/utils/icons.tsx +2 -2
  184. package/src/demo/DemoRouter.ts +8 -1
  185. package/src/demo/components/DemoLayout.tsx +12 -2
  186. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  187. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  188. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  189. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  190. package/src/demo/components/core/DemoButton.tsx +123 -103
  191. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  192. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  193. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  194. package/src/demo/components/shared/MacWindow.tsx +5 -11
  195. package/src/demo/components/shared/Showcase.tsx +28 -42
  196. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  197. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  198. package/dist/admin/Login-DHbYJKwg.js +0 -219
  199. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  200. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  201. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  202. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  203. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  204. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  205. package/dist/auth/Login-C7jIqf00.js +0 -219
  206. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  207. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  208. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  209. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  210. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  211. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  212. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  213. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  214. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  215. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  216. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  217. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  218. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  219. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  220. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  221. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  222. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  223. package/dist/demo/Login-CoYf_P_F.js +0 -219
  224. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  225. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  226. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  227. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  228. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  229. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  230. package/dist/demo/core-B7LNjM78.js.map +0 -1
  231. 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
+ });