nexus-shared 1.1.21 → 3.0.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 (376) hide show
  1. package/CHANGELOG.md +262 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1000 -0
  4. package/dist/Client.Index.d.ts +55 -0
  5. package/dist/Client.Index.js +60 -0
  6. package/dist/Components/Chats/Chat.d.ts +28 -0
  7. package/dist/Components/Chats/Chat.js +19 -0
  8. package/dist/Components/Chats/ChatButton.d.ts +26 -0
  9. package/dist/Components/Chats/ChatButton.js +41 -0
  10. package/dist/Components/Chats/ChatComposer.d.ts +41 -0
  11. package/dist/Components/Chats/ChatComposer.js +177 -0
  12. package/dist/Components/Chats/ChatConversations.d.ts +35 -0
  13. package/dist/Components/Chats/ChatConversations.js +38 -0
  14. package/dist/Components/Chats/ChatPanel.d.ts +66 -0
  15. package/dist/Components/Chats/ChatPanel.js +94 -0
  16. package/dist/Components/Chats/ChatParts.d.ts +87 -0
  17. package/dist/Components/Chats/ChatParts.js +100 -0
  18. package/dist/Components/Chats/ChatThread.d.ts +22 -0
  19. package/dist/Components/Chats/ChatThread.js +96 -0
  20. package/dist/Components/Documents/Button.d.ts +29 -0
  21. package/dist/Components/Documents/Button.js +11 -0
  22. package/dist/Components/Documents/Menu.d.ts +102 -0
  23. package/dist/Components/Documents/Menu.js +242 -0
  24. package/dist/Components/Documents/SplitButton.d.ts +64 -0
  25. package/dist/Components/Documents/SplitButton.js +129 -0
  26. package/dist/Components/Documents/TabButtons.d.ts +80 -0
  27. package/dist/Components/Documents/TabButtons.js +38 -0
  28. package/dist/Components/Forms/ApiForm.d.ts +23 -0
  29. package/dist/Components/Forms/ApiForm.js +100 -0
  30. package/dist/Components/Forms/Crud.d.ts +17 -0
  31. package/dist/Components/Forms/Crud.js +708 -0
  32. package/dist/Components/Forms/CrudParts.d.ts +15 -0
  33. package/dist/Components/Forms/CrudParts.js +36 -0
  34. package/dist/Components/Forms/ExcelImport.d.ts +42 -0
  35. package/dist/Components/Forms/ExcelImport.js +190 -0
  36. package/dist/Components/Forms/Form.d.ts +52 -0
  37. package/dist/Components/Forms/Form.js +323 -0
  38. package/dist/Components/Forms/SubmitForm.d.ts +65 -0
  39. package/dist/Components/Forms/SubmitForm.js +198 -0
  40. package/dist/Components/Inputs/Calendar.d.ts +69 -0
  41. package/dist/Components/Inputs/Calendar.js +258 -0
  42. package/dist/Components/Inputs/CheckBox.d.ts +53 -0
  43. package/dist/Components/Inputs/CheckBox.js +87 -0
  44. package/dist/Components/Inputs/CheckBoxGroup.d.ts +20 -0
  45. package/dist/Components/Inputs/CheckBoxGroup.js +80 -0
  46. package/dist/Components/Inputs/ChoiceField.d.ts +122 -0
  47. package/dist/Components/Inputs/ChoiceField.js +169 -0
  48. package/dist/Components/Inputs/DatePicker.d.ts +54 -0
  49. package/dist/Components/Inputs/DatePicker.js +246 -0
  50. package/dist/Components/Inputs/DateRangePicker.d.ts +62 -0
  51. package/dist/Components/Inputs/DateRangePicker.js +283 -0
  52. package/dist/Components/Inputs/DateTimePicker.d.ts +75 -0
  53. package/dist/Components/Inputs/DateTimePicker.js +400 -0
  54. package/dist/Components/Inputs/Dropdown.d.ts +117 -0
  55. package/dist/Components/Inputs/Dropdown.js +839 -0
  56. package/dist/Components/Inputs/DropdownParts.d.ts +84 -0
  57. package/dist/Components/Inputs/DropdownParts.js +102 -0
  58. package/dist/Components/Inputs/EditorShell.d.ts +45 -0
  59. package/dist/Components/Inputs/EditorShell.js +214 -0
  60. package/dist/Components/Inputs/Field.d.ts +53 -0
  61. package/dist/Components/Inputs/Field.js +16 -0
  62. package/dist/Components/Inputs/GroupForm.d.ts +20 -0
  63. package/dist/Components/Inputs/GroupForm.js +172 -0
  64. package/dist/Components/Inputs/InputField.d.ts +59 -0
  65. package/dist/Components/Inputs/InputField.js +169 -0
  66. package/dist/Components/Inputs/InputRenderer.d.ts +37 -0
  67. package/dist/Components/Inputs/InputRenderer.js +99 -0
  68. package/dist/Components/Inputs/MarkdownEditor.d.ts +67 -0
  69. package/dist/Components/Inputs/MarkdownEditor.js +289 -0
  70. package/dist/Components/Inputs/NumberBox.d.ts +53 -0
  71. package/dist/Components/Inputs/NumberBox.js +228 -0
  72. package/dist/Components/Inputs/RadioGroup.d.ts +20 -0
  73. package/dist/Components/Inputs/RadioGroup.js +43 -0
  74. package/dist/Components/Inputs/ReadOnlyNotice.d.ts +36 -0
  75. package/dist/Components/Inputs/ReadOnlyNotice.js +117 -0
  76. package/dist/Components/Inputs/RichTextEditor.d.ts +103 -0
  77. package/dist/Components/Inputs/RichTextEditor.js +1170 -0
  78. package/dist/Components/Inputs/RichTextParts.d.ts +63 -0
  79. package/dist/Components/Inputs/RichTextParts.js +157 -0
  80. package/dist/Components/Inputs/RowsInput.d.ts +115 -0
  81. package/dist/Components/Inputs/RowsInput.js +308 -0
  82. package/dist/Components/Inputs/Slider.d.ts +87 -0
  83. package/dist/Components/Inputs/Slider.js +216 -0
  84. package/dist/Components/Inputs/TabularForm.d.ts +27 -0
  85. package/dist/Components/Inputs/TabularForm.js +348 -0
  86. package/dist/Components/Inputs/TextArea.d.ts +43 -0
  87. package/dist/Components/Inputs/TextArea.js +31 -0
  88. package/dist/Components/Inputs/TextBox.d.ts +52 -0
  89. package/dist/Components/Inputs/TextBox.js +58 -0
  90. package/dist/Components/Inputs/TextField.d.ts +31 -0
  91. package/dist/Components/Inputs/TextField.js +35 -0
  92. package/dist/Components/Inputs/TimePanel.d.ts +34 -0
  93. package/dist/Components/Inputs/TimePanel.js +288 -0
  94. package/dist/Components/Inputs/TimePicker.d.ts +54 -0
  95. package/dist/Components/Inputs/TimePicker.js +240 -0
  96. package/dist/Components/Inputs/TreeView.d.ts +160 -0
  97. package/dist/Components/Inputs/TreeView.js +947 -0
  98. package/dist/Components/Layouts/MessageBox.d.ts +71 -0
  99. package/dist/Components/Layouts/MessageBox.js +104 -0
  100. package/dist/Components/Layouts/Popup.d.ts +92 -0
  101. package/dist/Components/Layouts/Popup.js +376 -0
  102. package/dist/Components/Layouts/PopupContext.d.ts +2 -0
  103. package/dist/Components/Layouts/PopupContext.js +4 -0
  104. package/dist/Components/Layouts/PopupDock.d.ts +22 -0
  105. package/dist/Components/Layouts/PopupDock.js +121 -0
  106. package/dist/Components/Layouts/PopupHost.d.ts +56 -0
  107. package/dist/Components/Layouts/PopupHost.js +163 -0
  108. package/dist/Components/Layouts/PopupRules.d.ts +30 -0
  109. package/dist/Components/Layouts/PopupRules.js +63 -0
  110. package/dist/Components/Layouts/ThemePicker.d.ts +13 -0
  111. package/dist/Components/Layouts/ThemePicker.js +22 -0
  112. package/dist/Components/Layouts/ThemeScript.d.ts +14 -0
  113. package/dist/Components/Layouts/ThemeScript.js +13 -0
  114. package/dist/Components/Layouts/ThemeSwitcher.d.ts +13 -0
  115. package/dist/Components/Layouts/ThemeSwitcher.js +49 -0
  116. package/dist/Components/Layouts/Toaster.d.ts +76 -0
  117. package/dist/Components/Layouts/Toaster.js +172 -0
  118. package/dist/Components/Viewers/DataTable.d.ts +25 -0
  119. package/dist/Components/Viewers/DataTable.js +596 -0
  120. package/dist/Components/Viewers/DataTableColumns.d.ts +28 -0
  121. package/dist/Components/Viewers/DataTableColumns.js +243 -0
  122. package/dist/Components/Viewers/DataTableParts.d.ts +138 -0
  123. package/dist/Components/Viewers/DataTableParts.js +157 -0
  124. package/dist/Components/Viewers/MarkdownView.d.ts +26 -0
  125. package/dist/Components/Viewers/MarkdownView.js +79 -0
  126. package/dist/Components/Viewers/RichTextView.d.ts +18 -0
  127. package/dist/Components/Viewers/RichTextView.js +17 -0
  128. package/dist/Helpers/AnimationHelpers.d.ts +6 -0
  129. package/dist/Helpers/AnimationHelpers.js +35 -0
  130. package/dist/Helpers/ApiClient.d.ts +96 -0
  131. package/dist/Helpers/ApiClient.js +200 -0
  132. package/dist/Helpers/ApiFormHelpers.d.ts +49 -0
  133. package/dist/Helpers/ApiFormHelpers.js +120 -0
  134. package/dist/Helpers/ApiModules.d.ts +131 -0
  135. package/dist/Helpers/ApiModules.js +195 -0
  136. package/dist/Helpers/ApiResponses.d.ts +51 -0
  137. package/dist/Helpers/ApiResponses.js +250 -0
  138. package/dist/Helpers/ApiRoutes.d.ts +140 -0
  139. package/dist/Helpers/ApiRoutes.js +183 -0
  140. package/dist/Helpers/ApiToasts.d.ts +21 -0
  141. package/dist/Helpers/ApiToasts.js +22 -0
  142. package/dist/Helpers/ChatBackend.d.ts +134 -0
  143. package/dist/Helpers/ChatBackend.js +332 -0
  144. package/dist/Helpers/ChatHelpers.d.ts +189 -0
  145. package/dist/Helpers/ChatHelpers.js +486 -0
  146. package/dist/Helpers/ChatHooks.d.ts +81 -0
  147. package/dist/Helpers/ChatHooks.js +175 -0
  148. package/dist/Helpers/ChatStore.d.ts +132 -0
  149. package/dist/Helpers/ChatStore.js +394 -0
  150. package/dist/Helpers/ChatSummaries.d.ts +39 -0
  151. package/dist/Helpers/ChatSummaries.js +118 -0
  152. package/dist/Helpers/ClassHelpers.d.ts +3 -0
  153. package/dist/Helpers/ClassHelpers.js +4 -0
  154. package/dist/Helpers/CrudBackend.d.ts +98 -0
  155. package/dist/Helpers/CrudBackend.js +214 -0
  156. package/dist/Helpers/CrudHelpers.d.ts +111 -0
  157. package/dist/Helpers/CrudHelpers.js +267 -0
  158. package/dist/Helpers/DateHelpers.d.ts +88 -0
  159. package/dist/Helpers/DateHelpers.js +363 -0
  160. package/dist/Helpers/DatePreferences.d.ts +14 -0
  161. package/dist/Helpers/DatePreferences.js +94 -0
  162. package/dist/Helpers/DateTimeHelpers.d.ts +87 -0
  163. package/dist/Helpers/DateTimeHelpers.js +286 -0
  164. package/dist/Helpers/DragHelpers.d.ts +129 -0
  165. package/dist/Helpers/DragHelpers.js +281 -0
  166. package/dist/Helpers/DropdownHelpers.d.ts +56 -0
  167. package/dist/Helpers/DropdownHelpers.js +180 -0
  168. package/dist/Helpers/ExcelBackend.d.ts +106 -0
  169. package/dist/Helpers/ExcelBackend.js +290 -0
  170. package/dist/Helpers/ExcelHelpers.d.ts +98 -0
  171. package/dist/Helpers/ExcelHelpers.js +302 -0
  172. package/dist/Helpers/FormDrafts.d.ts +18 -0
  173. package/dist/Helpers/FormDrafts.js +76 -0
  174. package/dist/Helpers/FormStore.d.ts +233 -0
  175. package/dist/Helpers/FormStore.js +752 -0
  176. package/dist/Helpers/InputParamsHelpers.d.ts +79 -0
  177. package/dist/Helpers/InputParamsHelpers.js +388 -0
  178. package/dist/Helpers/MarkdownEditing.d.ts +27 -0
  179. package/dist/Helpers/MarkdownEditing.js +250 -0
  180. package/dist/Helpers/MarkdownHelpers.d.ts +82 -0
  181. package/dist/Helpers/MarkdownHelpers.js +775 -0
  182. package/dist/Helpers/MessageBuilder.d.ts +74 -0
  183. package/dist/Helpers/MessageBuilder.js +252 -0
  184. package/dist/Helpers/NepaliCalendar.d.ts +25 -0
  185. package/dist/Helpers/NepaliCalendar.js +107 -0
  186. package/dist/Helpers/NumberHelpers.d.ts +71 -0
  187. package/dist/Helpers/NumberHelpers.js +202 -0
  188. package/dist/Helpers/Permissions.d.ts +62 -0
  189. package/dist/Helpers/Permissions.js +133 -0
  190. package/dist/Helpers/PopoverHelpers.d.ts +68 -0
  191. package/dist/Helpers/PopoverHelpers.js +195 -0
  192. package/dist/Helpers/RichTextHelpers.d.ts +77 -0
  193. package/dist/Helpers/RichTextHelpers.js +1072 -0
  194. package/dist/Helpers/RowsStore.d.ts +166 -0
  195. package/dist/Helpers/RowsStore.js +606 -0
  196. package/dist/Helpers/TableColumns.d.ts +47 -0
  197. package/dist/Helpers/TableColumns.js +282 -0
  198. package/dist/Helpers/TableExport.d.ts +30 -0
  199. package/dist/Helpers/TableExport.js +97 -0
  200. package/dist/Helpers/TableHelpers.d.ts +110 -0
  201. package/dist/Helpers/TableHelpers.js +301 -0
  202. package/dist/Helpers/TableStore.d.ts +142 -0
  203. package/dist/Helpers/TableStore.js +530 -0
  204. package/dist/Helpers/ThemeHelpers.d.ts +15 -0
  205. package/dist/Helpers/ThemeHelpers.js +16 -0
  206. package/dist/Helpers/TimeHelpers.d.ts +73 -0
  207. package/dist/Helpers/TimeHelpers.js +253 -0
  208. package/dist/Helpers/TreeStore.d.ts +188 -0
  209. package/dist/Helpers/TreeStore.js +577 -0
  210. package/dist/Helpers/ValidationHelpers.d.ts +124 -0
  211. package/dist/Helpers/ValidationHelpers.js +301 -0
  212. package/dist/Interfaces/ApiInterfaces.d.ts +174 -0
  213. package/dist/Interfaces/ApiInterfaces.js +30 -0
  214. package/dist/Interfaces/ChatInterfaces.d.ts +240 -0
  215. package/{src/sso-client.tsx → dist/Interfaces/ChatInterfaces.js} +1 -1
  216. package/dist/Interfaces/CrudInterfaces.d.ts +232 -0
  217. package/dist/Interfaces/CrudInterfaces.js +1 -0
  218. package/dist/Interfaces/DateInterfaces.d.ts +154 -0
  219. package/dist/Interfaces/DateInterfaces.js +29 -0
  220. package/dist/Interfaces/ExcelInterfaces.d.ts +215 -0
  221. package/dist/Interfaces/ExcelInterfaces.js +45 -0
  222. package/dist/Interfaces/FormInterfaces.d.ts +402 -0
  223. package/dist/Interfaces/FormInterfaces.js +1 -0
  224. package/dist/Interfaces/InputInterfaces.d.ts +141 -0
  225. package/dist/Interfaces/InputInterfaces.js +1 -0
  226. package/dist/Interfaces/MessageInterfaces.d.ts +111 -0
  227. package/dist/Interfaces/MessageInterfaces.js +5 -0
  228. package/dist/Interfaces/TableInterfaces.d.ts +351 -0
  229. package/dist/Interfaces/TableInterfaces.js +1 -0
  230. package/dist/Interfaces/ThemeInterfaces.d.ts +17 -0
  231. package/dist/Interfaces/ThemeInterfaces.js +17 -0
  232. package/dist/Interfaces/TypeInterfaces.d.ts +4 -0
  233. package/dist/Interfaces/TypeInterfaces.js +1 -0
  234. package/dist/Server.Index.d.ts +2 -0
  235. package/dist/Server.Index.js +5 -0
  236. package/dist/Services/ApiProxy.d.ts +32 -0
  237. package/dist/Services/ApiProxy.js +111 -0
  238. package/dist/Services/BrowserApi.d.ts +95 -0
  239. package/dist/Services/BrowserApi.js +129 -0
  240. package/dist/Services/ChatApi.d.ts +37 -0
  241. package/dist/Services/ChatApi.js +98 -0
  242. package/dist/Services/ExcelApi.d.ts +46 -0
  243. package/dist/Services/ExcelApi.js +196 -0
  244. package/dist/Services/ServerApi.d.ts +54 -0
  245. package/dist/Services/ServerApi.js +78 -0
  246. package/dist/Services/ThemeService.d.ts +17 -0
  247. package/dist/Services/ThemeService.js +83 -0
  248. package/dist/Shared.Index.d.ts +51 -0
  249. package/dist/Shared.Index.js +55 -0
  250. package/package.json +85 -33
  251. package/src/Styles/Nexus.Base.css +70 -0
  252. package/src/Styles/Nexus.Button.css +153 -0
  253. package/src/Styles/Nexus.Calendar.css +275 -0
  254. package/src/Styles/Nexus.Chat.css +1489 -0
  255. package/src/Styles/Nexus.Choice.css +345 -0
  256. package/src/Styles/Nexus.Crud.css +161 -0
  257. package/src/Styles/Nexus.DateTime.css +81 -0
  258. package/src/Styles/Nexus.Dropdown.css +774 -0
  259. package/src/Styles/Nexus.Editor.css +297 -0
  260. package/src/Styles/Nexus.Excel.css +370 -0
  261. package/src/Styles/Nexus.Form.css +321 -0
  262. package/src/Styles/Nexus.Index.css +36 -0
  263. package/src/Styles/Nexus.Input.css +637 -0
  264. package/src/Styles/Nexus.Markdown.css +265 -0
  265. package/src/Styles/Nexus.Menu.css +259 -0
  266. package/src/Styles/Nexus.Popup.css +731 -0
  267. package/src/Styles/Nexus.RichText.css +463 -0
  268. package/src/Styles/Nexus.Rows.css +596 -0
  269. package/src/Styles/Nexus.Slider.css +278 -0
  270. package/src/Styles/Nexus.Tab.Buttons.css +419 -0
  271. package/src/Styles/Nexus.Table.css +1296 -0
  272. package/src/Styles/Nexus.Theme.Picker.css +232 -0
  273. package/src/Styles/Nexus.Themes.css +194 -0
  274. package/src/Styles/Nexus.Time.css +147 -0
  275. package/src/Styles/Nexus.Toast.css +265 -0
  276. package/src/Styles/Nexus.Tokens.css +72 -0
  277. package/src/Styles/Nexus.Tree.css +435 -0
  278. package/src/api-services/authentication-service.tsx +0 -23
  279. package/src/api-services/preference-service.tsx +0 -5
  280. package/src/api-services/system-service.tsx +0 -29
  281. package/src/client.ts +0 -31
  282. package/src/components/documents/button.tsx +0 -133
  283. package/src/components/documents/icon-box.tsx +0 -93
  284. package/src/components/documents/page-title.tsx +0 -7
  285. package/src/components/documents/tab-button.tsx +0 -172
  286. package/src/components/documents/tag.tsx +0 -30
  287. package/src/components/index.js +0 -0
  288. package/src/components/inputs/checkbox-input.tsx +0 -66
  289. package/src/components/inputs/input-box.tsx +0 -48
  290. package/src/components/inputs/input-element.tsx +0 -65
  291. package/src/components/inputs/input-form.tsx +0 -164
  292. package/src/components/inputs/input.tsx +0 -181
  293. package/src/components/inputs/number-input.tsx +0 -108
  294. package/src/components/inputs/radiobox-input.tsx +0 -53
  295. package/src/components/inputs/textarea-input.tsx +0 -47
  296. package/src/components/inputs/textbox-input.tsx +0 -45
  297. package/src/components/layouts/global-dialogbox.tsx +0 -431
  298. package/src/components/layouts/global-layout.tsx +0 -64
  299. package/src/components/layouts/layout-helpers.tsx +0 -20
  300. package/src/components/layouts/panels/user-panel.tsx +0 -112
  301. package/src/components/layouts/utility-menu.tsx +0 -49
  302. package/src/components/panels/theme-panel.tsx +0 -46
  303. package/src/helpers/bitwise-helpers.tsx +0 -11
  304. package/src/helpers/browser-helpers.tsx +0 -156
  305. package/src/helpers/datasource-helpers.tsx +0 -99
  306. package/src/helpers/element-helpers.tsx +0 -123
  307. package/src/helpers/input-helpers.tsx +0 -74
  308. package/src/helpers/string-helpers.tsx +0 -28
  309. package/src/helpers/utility-helpers.tsx +0 -45
  310. package/src/helpers/validation-helpers.tsx +0 -302
  311. package/src/index.ts +0 -26
  312. package/src/interface.ts +0 -19
  313. package/src/interfaces/auth-token-interfaces.tsx +0 -6
  314. package/src/interfaces/browser-interfaces.tsx +0 -36
  315. package/src/interfaces/button-interfaces.tsx +0 -63
  316. package/src/interfaces/datasource-interfaces.tsx +0 -22
  317. package/src/interfaces/datatable-interfaces.tsx +0 -25
  318. package/src/interfaces/dialogbox-interfaces.tsx +0 -5
  319. package/src/interfaces/exception-interfaces.tsx +0 -99
  320. package/src/interfaces/http-interfaces.tsx +0 -129
  321. package/src/interfaces/icon-interfaces.tsx +0 -129
  322. package/src/interfaces/input-interfaces.tsx +0 -410
  323. package/src/interfaces/layout-interfaces.tsx +0 -191
  324. package/src/interfaces/menu-interfaces.tsx +0 -53
  325. package/src/interfaces/message-interfaces.tsx +0 -32
  326. package/src/interfaces/permission-interfaces.tsx +0 -9
  327. package/src/interfaces/storage-interfaces.tsx +0 -5
  328. package/src/interfaces/system-interfaces.tsx +0 -22
  329. package/src/interfaces/theme-interfaces.tsx +0 -123
  330. package/src/interfaces/type-interfaces.tsx +0 -28
  331. package/src/interfaces/user-interfaces.tsx +0 -47
  332. package/src/nexus-client.tsx +0 -21
  333. package/src/nexus.environments.tsx +0 -66
  334. package/src/proxy-api/proxy-backend.tsx +0 -60
  335. package/src/proxy-api/proxy-constants.tsx +0 -28
  336. package/src/proxy-api/proxy-helpers.tsx +0 -91
  337. package/src/proxy-api-client.tsx +0 -1
  338. package/src/proxy-api-server.tsx +0 -2
  339. package/src/services/http-client-services.tsx +0 -75
  340. package/src/services/http-services.tsx +0 -158
  341. package/src/services/loader-service.tsx +0 -185
  342. package/src/services/localstorage-service.tsx +0 -119
  343. package/src/services/message-services.tsx +0 -383
  344. package/src/services/theme-service.tsx +0 -163
  345. package/src/services/user-services.tsx +0 -10
  346. package/src/sso-config/auth-token-validation.ts +0 -16
  347. package/src/sso-config/callback-route.tsx +0 -35
  348. package/src/sso-config/cookie-encryption.ts +0 -51
  349. package/src/sso-config/cookie-helpers.tsx +0 -102
  350. package/src/sso-config/forgot-password-route.tsx +0 -36
  351. package/src/sso-config/oauth-callback-state.ts +0 -61
  352. package/src/sso-config/pkce-helpers.ts +0 -9
  353. package/src/sso-config/provider-complete-route.tsx +0 -18
  354. package/src/sso-config/redirect-context-actions.tsx +0 -45
  355. package/src/sso-config/redirect-context-helpers.tsx +0 -159
  356. package/src/sso-config/redirect-context-persist.tsx +0 -18
  357. package/src/sso-config/redirect-context-route.tsx +0 -45
  358. package/src/sso-config/refresh-route.tsx +0 -23
  359. package/src/sso-config/sign-in-route.tsx +0 -74
  360. package/src/sso-config/sign-out-route.tsx +0 -57
  361. package/src/sso-config/sign-up-route.tsx +0 -57
  362. package/src/sso-config/sso-backend-flow.ts +0 -38
  363. package/src/sso-config/sso-complete-route.tsx +0 -50
  364. package/src/sso-config/sso-config.ts +0 -59
  365. package/src/sso-config/sso-interfaces.tsx +0 -99
  366. package/src/sso-config/sso-response-helpers.tsx +0 -20
  367. package/src/sso-server.tsx +0 -21
  368. package/src/styles/nexus.animation.css +0 -269
  369. package/src/styles/nexus.core.css +0 -119
  370. package/src/styles/nexus.dialog.css +0 -144
  371. package/src/styles/nexus.grid-view.css +0 -42
  372. package/src/styles/nexus.icon.css +0 -51
  373. package/src/styles/nexus.input.css +0 -207
  374. package/src/styles/nexus.loader.css +0 -11
  375. package/src/styles/nexus.logic.css +0 -47
  376. package/src/styles/nexus.utility.css +0 -347
@@ -0,0 +1,124 @@
1
+ import type { DateRange, DateRangeRules, DateRules, DateTimeRules, TimeRules } from "../Interfaces/DateInterfaces.ts";
2
+ import type { CheckRules, NumberRules, OptionValue, SelectionRules, TextRules } from "../Interfaces/InputInterfaces.ts";
3
+ import { type DateTimeFormatOptions } from "./DateTimeHelpers.ts";
4
+ export declare const DEFAULT_FIELD_NAME = "This field";
5
+ /**
6
+ * Common patterns, each with a message that says what to type. Use them as `pattern={TEXT_PATTERNS.email}`.
7
+ * Names and messages accept letters from any language.
8
+ */
9
+ export declare const TEXT_PATTERNS: {
10
+ readonly email: {
11
+ readonly source: "[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}";
12
+ readonly message: "Enter an email address like name@example.com.";
13
+ };
14
+ readonly username: {
15
+ readonly source: "[A-Za-z0-9]+(?:[._\\-][A-Za-z0-9]+)*";
16
+ readonly message: "Use letters and numbers, with single dots, dashes, or underscores between them.";
17
+ };
18
+ readonly fullName: {
19
+ readonly source: "[\\p{L}\\p{M}]+(?:[ .'\\-]{1,2}[\\p{L}\\p{M}]+)*\\.?";
20
+ readonly message: "Use letters, with spaces, dots, apostrophes, or dashes between words.";
21
+ };
22
+ readonly phone: {
23
+ readonly source: "\\+?(?:[0-9][ \\-]?){6,14}[0-9]";
24
+ readonly message: "Enter a phone number of 7 to 15 digits, like +977 9812345678.";
25
+ };
26
+ readonly mobileNumber: {
27
+ readonly source: "[0-9]{10}";
28
+ readonly message: "Enter a 10-digit mobile number.";
29
+ };
30
+ readonly password: {
31
+ readonly source: "(?=.*\\p{Ll})(?=.*\\p{Lu})(?=.*[0-9])(?=.*[^\\p{L}0-9]).{8,64}";
32
+ readonly message: "Use 8 to 64 characters with an upper and a lower case letter, a number, and a symbol.";
33
+ };
34
+ readonly url: {
35
+ readonly source: "https?://[^\\s/$.?#][^\\s]*";
36
+ readonly message: "Enter a web address starting with http:// or https://.";
37
+ };
38
+ readonly digits: {
39
+ readonly source: "[0-9]+";
40
+ readonly message: "Use digits only.";
41
+ };
42
+ };
43
+ export declare const requiredMessage: (fieldName?: string) => string;
44
+ export declare const minLengthMessage: (fieldName: string, min: number) => string;
45
+ export declare const maxLengthMessage: (fieldName: string, max: number) => string;
46
+ export declare const invalidMessage: (fieldName?: string) => string;
47
+ export declare const notNumberMessage: (fieldName?: string) => string;
48
+ export declare const minValueMessage: (fieldName: string, min: string) => string;
49
+ export declare const maxValueMessage: (fieldName: string, max: string) => string;
50
+ export declare const uncheckedMessage: (fieldName?: string) => string;
51
+ export declare const minChoicesMessage: (fieldName: string, min: number) => string;
52
+ export declare const invalidDateMessage: (fieldName: string | undefined, example: string) => string;
53
+ export declare const minDateMessage: (fieldName: string, min: string) => string;
54
+ export declare const maxDateMessage: (fieldName: string, max: string) => string;
55
+ export declare const invalidDateRangeMessage: (fieldName: string | undefined, example: string) => string;
56
+ export declare const missingEndMessage: (fieldName?: string) => string;
57
+ export declare const missingStartMessage: (fieldName?: string) => string;
58
+ export declare const minStartMessage: (fieldName: string, min: string) => string;
59
+ export declare const maxEndMessage: (fieldName: string, max: string) => string;
60
+ export declare const minDistanceMessage: (fieldName: string, days: number) => string;
61
+ export declare const maxDistanceMessage: (fieldName: string, days: number) => string;
62
+ export declare const invalidTimeMessage: (fieldName: string | undefined, example: string) => string;
63
+ export declare const minTimeMessage: (fieldName: string, min: string) => string;
64
+ export declare const maxTimeMessage: (fieldName: string, max: string) => string;
65
+ export declare const timeRangeMessage: (fieldName: string, min: string, max: string) => string;
66
+ export declare const timeStepMessage: (fieldName: string, step: string, before: string, after: string) => string;
67
+ export declare const invalidDateTimeMessage: (fieldName: string | undefined, example: string) => string;
68
+ export declare const minDateTimeMessage: (fieldName: string, min: string) => string;
69
+ export declare const maxDateTimeMessage: (fieldName: string, max: string) => string;
70
+ export declare const maxChoicesMessage: (fieldName: string, max: number) => string;
71
+ export declare const minRowsMessage: (min: number, item: string, items: string) => string;
72
+ export declare const maxRowsMessage: (max: number, item: string, items: string) => string;
73
+ /** A radio column that one row must have on: "Choose the primary address." */
74
+ export declare const chooseRowMessage: (fieldName: string, item: string) => string;
75
+ /** A value that must differ between rows: "Email is the same as in row 1." */
76
+ export declare const duplicateRowMessage: (fieldName: string, item: string, position: number) => string;
77
+ /**
78
+ * Checks text against its rules and returns the first message, or `null` when the value is valid.
79
+ * Pure and DOM-free, so a form can validate thousands of values on submit, including fields not on screen.
80
+ * The value is trimmed first: " " counts as empty.
81
+ */
82
+ export declare function validateText(value: string | null | undefined, rules: TextRules, fieldName?: string): string | null;
83
+ /**
84
+ * Checks a number against its rules and returns the first message, or `null` when the value is valid.
85
+ * `null` means an empty field; `NaN` means text that is not a number. Pure and DOM-free, like `validateText`.
86
+ * `format` writes the limits in messages, e.g. `value => formatNumber(value, { grouping: true })` for "at least 1,000".
87
+ */
88
+ export declare function validateNumber(value: number | null | undefined, rules: NumberRules, fieldName?: string, format?: (value: number) => string): string | null;
89
+ /**
90
+ * Checks a date against its rules and returns the first message, or `null` when valid. The value is an ISO date,
91
+ * "" or `null` for an empty field, or any other text for something typed that is not a date. Pure, like `validateText`.
92
+ * `format` writes dates in messages the way the user sees them, e.g. `iso => formatDate(iso, preferences)`.
93
+ */
94
+ export declare function validateDate(value: string | null | undefined, rules: DateRules, fieldName?: string, format?: (iso: string) => string): string | null;
95
+ /**
96
+ * Checks a date range against its rules and returns the first message, or `null` when valid. The value is a pair
97
+ * of ISO dates (an end not chosen is `null`), "" or `null` for an empty field, or any other text for something
98
+ * typed that is not a range. A range with one end only is never valid. Pure, like `validateDate`; `format` writes
99
+ * dates in messages the way the user sees them.
100
+ */
101
+ export declare function validateDateRange(value: DateRange | string | null | undefined, rules: DateRangeRules, fieldName?: string, format?: (iso: string) => string): string | null;
102
+ /**
103
+ * Checks a time against its rules and returns the first message, or `null` when valid. The value is an ISO time,
104
+ * "" or `null` for an empty field, or any other text for something typed that is not a time. Limits are inclusive,
105
+ * and run past midnight when `max` is earlier than `min`; `step` counts seconds from midnight. Pure, like
106
+ * `validateDate`; `format` writes times in messages the way the user sees them, e.g. `iso => formatTime(iso, options)`.
107
+ */
108
+ export declare function validateTime(value: string | null | undefined, rules: TimeRules, fieldName?: string, format?: (iso: string) => string): string | null;
109
+ /**
110
+ * Checks a date-time against its rules and returns the first message, or `null` when valid. The value is a UTC ISO
111
+ * date-time ("2026-09-17T08:45:00.000Z"), "" or `null` for an empty field, or any other text for something typed that
112
+ * is not a date-time. `min` and `max` compare moments. `minTime`, `maxTime`, and `step` check the time of day the
113
+ * value shows in `options.timeZone` (the browser's by default), to the precision shown: seconds count only when the
114
+ * step has them. Pure, like `validateTime`; `options` are the settings the field is shown with, so messages read
115
+ * like the box.
116
+ */
117
+ export declare function validateDateTime(value: string | null | undefined, rules: DateTimeRules, fieldName?: string, options?: DateTimeFormatOptions): string | null;
118
+ /**
119
+ * Checks a single checkbox or switch. The field name is optional: a checkbox label is usually a sentence
120
+ * ("I accept the terms"), so without one the message is "Check this box to continue."
121
+ */
122
+ export declare function validateCheck(checked: boolean, rules: CheckRules, fieldName?: string): string | null;
123
+ /** Checks the values chosen in a checkbox group or a radio group. Pure, like `validateText`. */
124
+ export declare function validateSelection<T extends OptionValue>(values: readonly T[], rules: SelectionRules<T>, fieldName?: string): string | null;
@@ -0,0 +1,301 @@
1
+ import { addDays, DATE_RANGE_SEPARATOR, diffDays, isIsoDate, todayIsoDate, toIsoDate } from "./DateHelpers.js";
2
+ import { formatDateTime, fromLocalDateTime, isUtcDateTime, timeScriptOf, todayIsoDateIn, toLocalDateTime, toUtcDateTime } from "./DateTimeHelpers.js";
3
+ import { describeTimeStep, formatTime, isIsoTime, isSecondsInRange, normalizeTimeStep, secondsToIsoTime, timeToSeconds, toIsoTime } from "./TimeHelpers.js";
4
+ export const DEFAULT_FIELD_NAME = "This field";
5
+ /**
6
+ * Common patterns, each with a message that says what to type. Use them as `pattern={TEXT_PATTERNS.email}`.
7
+ * Names and messages accept letters from any language.
8
+ */
9
+ export const TEXT_PATTERNS = {
10
+ email: {
11
+ source: "[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}",
12
+ message: "Enter an email address like name@example.com.",
13
+ },
14
+ username: {
15
+ source: "[A-Za-z0-9]+(?:[._\\-][A-Za-z0-9]+)*",
16
+ message: "Use letters and numbers, with single dots, dashes, or underscores between them.",
17
+ },
18
+ fullName: {
19
+ source: "[\\p{L}\\p{M}]+(?:[ .'\\-]{1,2}[\\p{L}\\p{M}]+)*\\.?",
20
+ message: "Use letters, with spaces, dots, apostrophes, or dashes between words.",
21
+ },
22
+ phone: {
23
+ source: "\\+?(?:[0-9][ \\-]?){6,14}[0-9]",
24
+ message: "Enter a phone number of 7 to 15 digits, like +977 9812345678.",
25
+ },
26
+ mobileNumber: {
27
+ source: "[0-9]{10}",
28
+ message: "Enter a 10-digit mobile number.",
29
+ },
30
+ password: {
31
+ source: "(?=.*\\p{Ll})(?=.*\\p{Lu})(?=.*[0-9])(?=.*[^\\p{L}0-9]).{8,64}",
32
+ message: "Use 8 to 64 characters with an upper and a lower case letter, a number, and a symbol.",
33
+ },
34
+ url: {
35
+ source: "https?://[^\\s/$.?#][^\\s]*",
36
+ message: "Enter a web address starting with http:// or https://.",
37
+ },
38
+ digits: {
39
+ source: "[0-9]+",
40
+ message: "Use digits only.",
41
+ },
42
+ };
43
+ export const requiredMessage = (fieldName = DEFAULT_FIELD_NAME) => `${fieldName} is required.`;
44
+ export const minLengthMessage = (fieldName, min) => `${fieldName} must be at least ${min} characters.`;
45
+ export const maxLengthMessage = (fieldName, max) => `${fieldName} cannot be longer than ${max} characters.`;
46
+ export const invalidMessage = (fieldName = DEFAULT_FIELD_NAME) => (fieldName === DEFAULT_FIELD_NAME ? "Enter a valid value." : `${fieldName} is not valid.`);
47
+ export const notNumberMessage = (fieldName = DEFAULT_FIELD_NAME) => (fieldName === DEFAULT_FIELD_NAME ? "Enter a number." : `${fieldName} must be a number.`);
48
+ export const minValueMessage = (fieldName, min) => `${fieldName} must be at least ${min}.`;
49
+ export const maxValueMessage = (fieldName, max) => `${fieldName} cannot be more than ${max}.`;
50
+ export const uncheckedMessage = (fieldName) => (fieldName ? `${fieldName} must be checked.` : "Check this box to continue.");
51
+ export const minChoicesMessage = (fieldName, min) => `${fieldName} needs at least ${min} choices.`;
52
+ export const invalidDateMessage = (fieldName = DEFAULT_FIELD_NAME, example) => fieldName === DEFAULT_FIELD_NAME ? `Enter a date like ${example}.` : `${fieldName} must be a date like ${example}.`;
53
+ export const minDateMessage = (fieldName, min) => `${fieldName} must be on or after ${min}.`;
54
+ export const maxDateMessage = (fieldName, max) => `${fieldName} cannot be after ${max}.`;
55
+ export const invalidDateRangeMessage = (fieldName = DEFAULT_FIELD_NAME, example) => fieldName === DEFAULT_FIELD_NAME ? `Enter a range like ${example}.` : `${fieldName} must be a range like ${example}.`;
56
+ export const missingEndMessage = (fieldName = DEFAULT_FIELD_NAME) => `${fieldName} needs an end date.`;
57
+ export const missingStartMessage = (fieldName = DEFAULT_FIELD_NAME) => `${fieldName} needs a start date.`;
58
+ export const minStartMessage = (fieldName, min) => `${fieldName} must start on or after ${min}.`;
59
+ export const maxEndMessage = (fieldName, max) => `${fieldName} cannot end after ${max}.`;
60
+ export const minDistanceMessage = (fieldName, days) => `${fieldName} must be at least ${days} ${days === 1 ? "day" : "days"} long.`;
61
+ export const maxDistanceMessage = (fieldName, days) => `${fieldName} cannot be longer than ${days} ${days === 1 ? "day" : "days"}.`;
62
+ export const invalidTimeMessage = (fieldName = DEFAULT_FIELD_NAME, example) => fieldName === DEFAULT_FIELD_NAME ? `Enter a time like ${example}.` : `${fieldName} must be a time like ${example}.`;
63
+ export const minTimeMessage = (fieldName, min) => `${fieldName} must be ${min} or later.`;
64
+ export const maxTimeMessage = (fieldName, max) => `${fieldName} cannot be later than ${max}.`;
65
+ export const timeRangeMessage = (fieldName, min, max) => `${fieldName} must be between ${min} and ${max}.`;
66
+ export const timeStepMessage = (fieldName, step, before, after) => `${fieldName} must be in steps of ${step}, like ${before} or ${after}.`;
67
+ export const invalidDateTimeMessage = (fieldName = DEFAULT_FIELD_NAME, example) => fieldName === DEFAULT_FIELD_NAME ? `Enter a date and time like ${example}.` : `${fieldName} must be a date and time like ${example}.`;
68
+ export const minDateTimeMessage = (fieldName, min) => `${fieldName} must be ${min} or later.`;
69
+ export const maxDateTimeMessage = (fieldName, max) => `${fieldName} cannot be later than ${max}.`;
70
+ export const maxChoicesMessage = (fieldName, max) => `${fieldName} allows at most ${max} ${max === 1 ? "choice" : "choices"}.`;
71
+ /* Tabular and group forms. `item` and `items` are the row's name in lower case: "address", "addresses". */
72
+ export const minRowsMessage = (min, item, items) => (min <= 1 ? `Add at least one ${item}.` : `Add at least ${min} ${items}.`);
73
+ export const maxRowsMessage = (max, item, items) => (max <= 1 ? `Only one ${item} is allowed.` : `Only ${max} ${items} are allowed.`);
74
+ /** A radio column that one row must have on: "Choose the primary address." */
75
+ export const chooseRowMessage = (fieldName, item) => `Choose the ${fieldName} ${item}.`;
76
+ /** A value that must differ between rows: "Email is the same as in row 1." */
77
+ export const duplicateRowMessage = (fieldName, item, position) => `${fieldName} is the same as in ${item} ${position}.`;
78
+ // Compiled once per source: a large form validates the same few patterns thousands of times.
79
+ const compiledPatterns = new Map();
80
+ function toRegExp(pattern) {
81
+ if (pattern instanceof RegExp) {
82
+ pattern.lastIndex = 0;
83
+ return pattern;
84
+ }
85
+ const source = typeof pattern === "string" ? pattern : pattern.source;
86
+ let compiled = compiledPatterns.get(source);
87
+ if (!compiled) {
88
+ // Anchored like the HTML pattern attribute; the "u" flag lets patterns use \p{L} for letters in any language.
89
+ compiled = new RegExp(`^(?:${source})$`, "u");
90
+ compiledPatterns.set(source, compiled);
91
+ }
92
+ return compiled;
93
+ }
94
+ /**
95
+ * Checks text against its rules and returns the first message, or `null` when the value is valid.
96
+ * Pure and DOM-free, so a form can validate thousands of values on submit, including fields not on screen.
97
+ * The value is trimmed first: " " counts as empty.
98
+ */
99
+ export function validateText(value, rules, fieldName = DEFAULT_FIELD_NAME) {
100
+ const text = (value ?? "").trim();
101
+ if (text) {
102
+ const { minLength, maxLength, pattern } = rules;
103
+ if (minLength && text.length < minLength)
104
+ return minLengthMessage(fieldName, minLength);
105
+ if (maxLength && text.length > maxLength)
106
+ return maxLengthMessage(fieldName, maxLength);
107
+ if (pattern && !toRegExp(pattern).test(text)) {
108
+ return typeof pattern === "object" && !(pattern instanceof RegExp) ? pattern.message : (rules.patternMessage ?? invalidMessage(fieldName));
109
+ }
110
+ }
111
+ else if (rules.required) {
112
+ return requiredMessage(fieldName);
113
+ }
114
+ return rules.validate?.(text) || null;
115
+ }
116
+ /**
117
+ * Checks a number against its rules and returns the first message, or `null` when the value is valid.
118
+ * `null` means an empty field; `NaN` means text that is not a number. Pure and DOM-free, like `validateText`.
119
+ * `format` writes the limits in messages, e.g. `value => formatNumber(value, { grouping: true })` for "at least 1,000".
120
+ */
121
+ export function validateNumber(value, rules, fieldName = DEFAULT_FIELD_NAME, format = String) {
122
+ if (value === null || value === undefined) {
123
+ if (rules.required)
124
+ return requiredMessage(fieldName);
125
+ }
126
+ else if (Number.isNaN(value)) {
127
+ return notNumberMessage(fieldName);
128
+ }
129
+ else {
130
+ if (rules.min !== undefined && value < rules.min)
131
+ return minValueMessage(fieldName, format(rules.min));
132
+ if (rules.max !== undefined && value > rules.max)
133
+ return maxValueMessage(fieldName, format(rules.max));
134
+ }
135
+ return rules.validate?.(value ?? null) || null;
136
+ }
137
+ /**
138
+ * Checks a date against its rules and returns the first message, or `null` when valid. The value is an ISO date,
139
+ * "" or `null` for an empty field, or any other text for something typed that is not a date. Pure, like `validateText`.
140
+ * `format` writes dates in messages the way the user sees them, e.g. `iso => formatDate(iso, preferences)`.
141
+ */
142
+ export function validateDate(value, rules, fieldName = DEFAULT_FIELD_NAME, format = iso => iso) {
143
+ if (!value) {
144
+ if (rules.required)
145
+ return requiredMessage(fieldName);
146
+ }
147
+ else if (!isIsoDate(value)) {
148
+ return invalidDateMessage(fieldName, format(todayIsoDate()));
149
+ }
150
+ else {
151
+ const min = toIsoDate(rules.min);
152
+ if (min && value < min)
153
+ return minDateMessage(fieldName, format(min));
154
+ const max = toIsoDate(rules.max);
155
+ if (max && value > max)
156
+ return maxDateMessage(fieldName, format(max));
157
+ }
158
+ return rules.validate?.(value || null) || null;
159
+ }
160
+ /**
161
+ * Checks a date range against its rules and returns the first message, or `null` when valid. The value is a pair
162
+ * of ISO dates (an end not chosen is `null`), "" or `null` for an empty field, or any other text for something
163
+ * typed that is not a range. A range with one end only is never valid. Pure, like `validateDate`; `format` writes
164
+ * dates in messages the way the user sees them.
165
+ */
166
+ export function validateDateRange(value, rules, fieldName = DEFAULT_FIELD_NAME, format = iso => iso) {
167
+ if (typeof value === "string" && value) {
168
+ const today = todayIsoDate();
169
+ return invalidDateRangeMessage(fieldName, format(today) + DATE_RANGE_SEPARATOR + format(addDays(today, 3)));
170
+ }
171
+ const [start, end] = value && typeof value !== "string" ? value : [null, null];
172
+ if (!start && !end) {
173
+ if (rules.required)
174
+ return requiredMessage(fieldName);
175
+ }
176
+ else if (!end) {
177
+ return missingEndMessage(fieldName);
178
+ }
179
+ else if (!start) {
180
+ return missingStartMessage(fieldName);
181
+ }
182
+ else {
183
+ const min = toIsoDate(rules.min);
184
+ if (min && start < min)
185
+ return minStartMessage(fieldName, format(min));
186
+ const max = toIsoDate(rules.max);
187
+ if (max && end > max)
188
+ return maxEndMessage(fieldName, format(max));
189
+ const distance = diffDays(start, end);
190
+ if (rules.minDistance !== undefined && distance < rules.minDistance)
191
+ return minDistanceMessage(fieldName, rules.minDistance);
192
+ if (rules.maxDistance !== undefined && distance > rules.maxDistance)
193
+ return maxDistanceMessage(fieldName, rules.maxDistance);
194
+ }
195
+ return rules.validate?.([start, end]) || null;
196
+ }
197
+ /**
198
+ * Checks a time against its rules and returns the first message, or `null` when valid. The value is an ISO time,
199
+ * "" or `null` for an empty field, or any other text for something typed that is not a time. Limits are inclusive,
200
+ * and run past midnight when `max` is earlier than `min`; `step` counts seconds from midnight. Pure, like
201
+ * `validateDate`; `format` writes times in messages the way the user sees them, e.g. `iso => formatTime(iso, options)`.
202
+ */
203
+ export function validateTime(value, rules, fieldName = DEFAULT_FIELD_NAME, format = iso => iso) {
204
+ if (!value) {
205
+ if (rules.required)
206
+ return requiredMessage(fieldName);
207
+ }
208
+ else if (!isIsoTime(value)) {
209
+ return invalidTimeMessage(fieldName, format("14:30"));
210
+ }
211
+ else {
212
+ const time = timeToSeconds(value);
213
+ const step = normalizeTimeStep(rules.step);
214
+ // Times in messages have seconds only when the step or the time itself does.
215
+ const write = (seconds) => format(secondsToIsoTime(seconds, step % 60 !== 0 || seconds % 60 !== 0));
216
+ const min = toIsoTime(rules.min, true);
217
+ const max = toIsoTime(rules.max, true);
218
+ const from = min === null ? null : timeToSeconds(min);
219
+ const to = max === null ? null : timeToSeconds(max);
220
+ if (!isSecondsInRange(time, from, to)) {
221
+ if (from !== null && to !== null)
222
+ return timeRangeMessage(fieldName, write(from), write(to));
223
+ return from !== null ? minTimeMessage(fieldName, write(from)) : maxTimeMessage(fieldName, write(to));
224
+ }
225
+ if (time % step !== 0) {
226
+ const before = Math.floor(time / step) * step;
227
+ return timeStepMessage(fieldName, describeTimeStep(step), write(before), write(before + step));
228
+ }
229
+ }
230
+ return rules.validate?.(value || null) || null;
231
+ }
232
+ /**
233
+ * Checks a date-time against its rules and returns the first message, or `null` when valid. The value is a UTC ISO
234
+ * date-time ("2026-09-17T08:45:00.000Z"), "" or `null` for an empty field, or any other text for something typed that
235
+ * is not a date-time. `min` and `max` compare moments. `minTime`, `maxTime`, and `step` check the time of day the
236
+ * value shows in `options.timeZone` (the browser's by default), to the precision shown: seconds count only when the
237
+ * step has them. Pure, like `validateTime`; `options` are the settings the field is shown with, so messages read
238
+ * like the box.
239
+ */
240
+ export function validateDateTime(value, rules, fieldName = DEFAULT_FIELD_NAME, options = {}) {
241
+ const step = normalizeTimeStep(rules.step);
242
+ const seconds = step % 60 !== 0;
243
+ const shown = { ...options, seconds };
244
+ const writeTime = (time) => formatTime(secondsToIsoTime(time, true), { format: options.timeFormat, script: timeScriptOf(options), seconds });
245
+ if (!value) {
246
+ if (rules.required)
247
+ return requiredMessage(fieldName);
248
+ }
249
+ else if (!isUtcDateTime(value)) {
250
+ const example = fromLocalDateTime(todayIsoDateIn(options.timeZone), "14:30", options.timeZone);
251
+ return invalidDateTimeMessage(fieldName, formatDateTime(example, shown));
252
+ }
253
+ else {
254
+ const min = toUtcDateTime(rules.min, options.timeZone);
255
+ if (min && value < min)
256
+ return minDateTimeMessage(fieldName, formatDateTime(min, shown));
257
+ const max = toUtcDateTime(rules.max, options.timeZone);
258
+ if (max && value > max)
259
+ return maxDateTimeMessage(fieldName, formatDateTime(max, shown));
260
+ const total = timeToSeconds(toLocalDateTime(value, options.timeZone).time);
261
+ const time = seconds ? total : total - (total % 60);
262
+ const minTime = toIsoTime(rules.minTime, true);
263
+ const maxTime = toIsoTime(rules.maxTime, true);
264
+ const from = minTime === null ? null : timeToSeconds(minTime);
265
+ const to = maxTime === null ? null : timeToSeconds(maxTime);
266
+ if (!isSecondsInRange(time, from, to)) {
267
+ if (from !== null && to !== null)
268
+ return timeRangeMessage(fieldName, writeTime(from), writeTime(to));
269
+ return from !== null ? minTimeMessage(fieldName, writeTime(from)) : maxTimeMessage(fieldName, writeTime(to));
270
+ }
271
+ if (time % step !== 0) {
272
+ const before = Math.floor(time / step) * step;
273
+ return timeStepMessage(fieldName, describeTimeStep(step), writeTime(before), writeTime(before + step));
274
+ }
275
+ }
276
+ return rules.validate?.(value || null) || null;
277
+ }
278
+ /**
279
+ * Checks a single checkbox or switch. The field name is optional: a checkbox label is usually a sentence
280
+ * ("I accept the terms"), so without one the message is "Check this box to continue."
281
+ */
282
+ export function validateCheck(checked, rules, fieldName) {
283
+ if (rules.required && !checked)
284
+ return uncheckedMessage(fieldName);
285
+ return rules.validate?.(checked) || null;
286
+ }
287
+ /** Checks the values chosen in a checkbox group or a radio group. Pure, like `validateText`. */
288
+ export function validateSelection(values, rules, fieldName = DEFAULT_FIELD_NAME) {
289
+ const count = values.length;
290
+ if (count === 0) {
291
+ if (rules.required)
292
+ return requiredMessage(fieldName);
293
+ }
294
+ else {
295
+ if (rules.min !== undefined && count < rules.min)
296
+ return minChoicesMessage(fieldName, rules.min);
297
+ if (rules.max !== undefined && count > rules.max)
298
+ return maxChoicesMessage(fieldName, rules.max);
299
+ }
300
+ return rules.validate?.([...values]) || null;
301
+ }
@@ -0,0 +1,174 @@
1
+ import type { MessageAction } from "./MessageInterfaces.ts";
2
+ /** A module's value in an app's own enum: a number (`NexusModule.Identity`) or a string (`"hr"`). */
3
+ export type ApiModuleValue = string | number;
4
+ /**
5
+ * The Nexus backend modules, the modules of `NexusApiModules`. The values are the backend's `EModules` flags, so they
6
+ * can be combined and compared with permissions. Another backend has an enum of its own and its own `ApiModules` class.
7
+ *
8
+ * **These numbers are the backend's, not this package's.** A permission is a bitmask of them, so a value that differs
9
+ * from the backend by one bit does not fail loudly: it silently grants or denies the wrong module. `Chat` was added
10
+ * at bit 6 in the backend on 2026-09-25 and every module after it moved up one bit; this list moved with it, which
11
+ * changed the value of `Accounting` through `Portfolio`. See CHANGELOG.md.
12
+ */
13
+ export declare const NexusModule: {
14
+ /** The app's own API routes (`/api/...`), not a backend module. */
15
+ readonly None: 0;
16
+ readonly Migrations: number;
17
+ readonly Configuration: number;
18
+ readonly Identity: number;
19
+ readonly Enterprise: number;
20
+ readonly Drive: number;
21
+ readonly Message: number;
22
+ readonly Chat: number;
23
+ readonly Accounting: number;
24
+ readonly Report: number;
25
+ readonly Requisition: number;
26
+ readonly Tenant: number;
27
+ readonly Subscription: number;
28
+ readonly Reservation: number;
29
+ readonly School: number;
30
+ readonly Pharmacy: number;
31
+ readonly Staffing: number;
32
+ readonly Portfolio: number;
33
+ };
34
+ export type NexusModule = (typeof NexusModule)[keyof typeof NexusModule];
35
+ /**
36
+ * Where an app names its module enum for the types, once, next to its `defineApiModules`:
37
+ *
38
+ * @example
39
+ * export const MODULES = defineApiModules(new HrApiModules());
40
+ * declare module "nexus-shared" {
41
+ * interface ApiRegister { module: HrModule }
42
+ * }
43
+ *
44
+ * Every endpoint, call, API form, and CRUD then takes only those modules. Without it, the Nexus modules.
45
+ */
46
+ export interface ApiRegister {
47
+ }
48
+ /** The app's module type: the one named in `ApiRegister`, else `NexusModule`. */
49
+ export type AppModule = ApiRegister extends {
50
+ module: infer TModule extends ApiModuleValue;
51
+ } ? TModule : NexusModule;
52
+ /** One module of an app's API: its value, and how it is named. */
53
+ export interface ApiModuleInfo<TModule extends ApiModuleValue = ApiModuleValue> {
54
+ module: TModule;
55
+ /** Its name in proxy URLs: `/api/app/reservation/Room/NormalListing`. Letters, digits, dots, dashes, and underscores. */
56
+ key: string;
57
+ /** Its name in messages: "The Reservation API address is not set." */
58
+ label: string;
59
+ /** Where its root URL comes from, such as the environment variable `API_RESERVATION`. Named in messages when it is missing. */
60
+ env?: string;
61
+ }
62
+ export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
63
+ /** `json` sends the body as JSON; `form-data` as fields (files stay files, lists and objects go as JSON text). */
64
+ export type ApiBodyType = "json" | "form-data";
65
+ /** Query values: lists repeat their name, dates go as ISO text, and `null` or `undefined` values are left out. */
66
+ export type ApiQuery = Record<string, string | number | boolean | Date | null | undefined | readonly (string | number | boolean)[]>;
67
+ /**
68
+ * An API: which module serves it, its path under the module's root, and its method. Build them with `apiEndpoint` or
69
+ * `apiController`, once per app, and call them with `api` in the browser or `serverApi` on the server. The module is
70
+ * one of the app's (`AppModule`); its root, through the proxy or not, comes from the app's `ApiModules`.
71
+ */
72
+ export interface ApiEndpoint<TModule extends ApiModuleValue = AppModule> {
73
+ module: TModule;
74
+ /** Under the module's root, such as "Room/Detail/{id}". A `{name}` is filled from the call's `params`, then its body. */
75
+ path: string;
76
+ method: HttpMethod;
77
+ /** Default `json`. */
78
+ bodyType?: ApiBodyType;
79
+ /** Query values sent with every call; a call's own `query` adds to them. */
80
+ query?: ApiQuery;
81
+ /** What the call does, for its messages. Default: by method (`load` for GET, `delete` for DELETE, else `save`). */
82
+ action?: MessageAction;
83
+ /** What it acts on, for its messages: "room". A call's `subject` ("Room 204") replaces it. */
84
+ subject?: string;
85
+ }
86
+ /** Where a call goes: an endpoint, or a URL ("/api/demo-rooms", "https://…"). */
87
+ export type ApiTarget = ApiEndpoint | string;
88
+ /**
89
+ * One problem in a failed answer, as the backend explains it: plain words for the user, the codes behind them, and the
90
+ * input it is about. A backend answers every wrong field at once, so a failure can carry several.
91
+ */
92
+ export interface ApiErrorMessage {
93
+ /** What the user is shown: the server's own sentence ("This Region name already exists."). */
94
+ message: string;
95
+ /** The code of that exact refusal ("RGN_X009"), for the log and for a page to react to. Never shown to the user. */
96
+ messageCode?: string;
97
+ /** The kind of problem as a number (Nexus `errorCode`). Never shown to the user. */
98
+ errorCode?: number;
99
+ /** The input the message is about, as the server names it ("regionName"); several named with "|". */
100
+ inputName?: string;
101
+ }
102
+ /** A server's answer, read as success or failure. Every call answers with one; it never throws for a failed request. */
103
+ export interface ApiResult<T = unknown> {
104
+ ok: boolean;
105
+ /** The HTTP status, when known. */
106
+ status?: number;
107
+ /** What the server sent back: the record, the list, the saved id. */
108
+ result?: T;
109
+ /** The server's own message (its problems joined, in its order), or one built for the failure by status. */
110
+ message?: string;
111
+ /** The first problem's code for its message, such as "RGN_X009" (Nexus `messageCode`). Never shown as the sentence. */
112
+ messageCode?: string;
113
+ /** The first problem's error number (Nexus `errorCode`). Never shown as the sentence. */
114
+ errorCode?: number;
115
+ /** Every problem the server explained, in its order. A failure it explained carries at least one. */
116
+ errorMessages?: ApiErrorMessage[];
117
+ /** Messages by field name, as the server names them ("Email", "addresses[1].city"); matched to inputs without case. */
118
+ errors?: Record<string, string>;
119
+ /** Nothing reached the server: offline, or the server is down. */
120
+ network?: boolean;
121
+ /** The server did not answer within the call's `timeout`. */
122
+ timeout?: boolean;
123
+ /** The caller stopped the call through its `signal`. Nothing is shown for it. */
124
+ aborted?: boolean;
125
+ }
126
+ /** A page of a list, as Nexus pagination APIs answer. */
127
+ export interface ApiPage<T = unknown> {
128
+ results: T[];
129
+ /** Every row the user may see. */
130
+ totalCount: number;
131
+ /** The rows that match the search and filters. */
132
+ filterCount: number;
133
+ }
134
+ /** What Nexus pagination APIs take. */
135
+ export interface ApiPageRequest {
136
+ searchKeyword?: string;
137
+ skipCount?: number;
138
+ maxCount?: number;
139
+ sorting?: string;
140
+ sortType?: "asc" | "desc";
141
+ }
142
+ /** Options of one call, on either side. */
143
+ export interface ApiCallOptions {
144
+ /** What is sent. GET sends no body. */
145
+ body?: unknown;
146
+ /** Fills `{name}` in the endpoint's path. Missing names are taken from the body. */
147
+ params?: Record<string, string | number | null | undefined>;
148
+ /** Query values, added to the endpoint's own. */
149
+ query?: ApiQuery;
150
+ /** Replaces the endpoint's method. */
151
+ method?: HttpMethod;
152
+ headers?: Record<string, string>;
153
+ bodyType?: ApiBodyType;
154
+ /** Stops the call. The answer is then `{ ok: false, aborted: true }`, and nothing is shown. */
155
+ signal?: AbortSignal;
156
+ /** Milliseconds to wait for an answer. Default: the client's, 60,000; 0 waits as long as the browser does. */
157
+ timeout?: number;
158
+ /** Tries again after a network failure or a 502, 503, or 504. Default 1 for GET, 0 for the rest (a save must not run twice). */
159
+ retries?: number;
160
+ credentials?: RequestCredentials;
161
+ /**
162
+ * Reads the answer. Default: the app's reader (`configureApi({ read })` / `configureServerApi({ read })`), else
163
+ * `readApiResponse`: Nexus answers, ASP.NET Core problem details, any JSON by its status.
164
+ */
165
+ read?: (body: unknown, status: number | undefined) => ApiResult;
166
+ /** What the call does, for its messages. Default: the endpoint's, or by method. */
167
+ action?: MessageAction;
168
+ /** What it acts on, for its messages: "Room 204". Default: the endpoint's. */
169
+ subject?: string;
170
+ /** How many it acts on: 3 → "3 rooms deleted." */
171
+ count?: number;
172
+ /** The plural of `subject` with a `count`, when adding "s" is wrong: "people". */
173
+ plural?: string;
174
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The Nexus backend modules, the modules of `NexusApiModules`. The values are the backend's `EModules` flags, so they
3
+ * can be combined and compared with permissions. Another backend has an enum of its own and its own `ApiModules` class.
4
+ *
5
+ * **These numbers are the backend's, not this package's.** A permission is a bitmask of them, so a value that differs
6
+ * from the backend by one bit does not fail loudly: it silently grants or denies the wrong module. `Chat` was added
7
+ * at bit 6 in the backend on 2026-09-25 and every module after it moved up one bit; this list moved with it, which
8
+ * changed the value of `Accounting` through `Portfolio`. See CHANGELOG.md.
9
+ */
10
+ export const NexusModule = {
11
+ /** The app's own API routes (`/api/...`), not a backend module. */
12
+ None: 0,
13
+ Migrations: 1 << 0,
14
+ Configuration: 1 << 1,
15
+ Identity: 1 << 2,
16
+ Enterprise: 1 << 3,
17
+ Drive: 1 << 4,
18
+ Message: 1 << 5,
19
+ Chat: 1 << 6,
20
+ Accounting: 1 << 7,
21
+ Report: 1 << 8,
22
+ Requisition: 1 << 9,
23
+ Tenant: 1 << 10,
24
+ Subscription: 1 << 11,
25
+ Reservation: 1 << 12,
26
+ School: 1 << 13,
27
+ Pharmacy: 1 << 14,
28
+ Staffing: 1 << 15,
29
+ Portfolio: 1 << 16,
30
+ };