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,202 @@
1
+ /** Default locale for number text. Fixed rather than the browser's, so server-rendered text matches the browser's. */
2
+ export const DEFAULT_NUMBER_LOCALE = "en-US";
3
+ /** Most digits a number field takes. A JavaScript number holds 15 significant digits exactly; beyond that, digits change. */
4
+ export const MAX_NUMBER_DIGITS = 15;
5
+ const symbolsByLocale = new Map();
6
+ const formatters = new Map();
7
+ // Direction marks some locales put around a minus sign; they are invisible and never part of the number.
8
+ const BIDI_MARKS = /[\u061c\u200e\u200f]/g;
9
+ // U+2212, the typographic minus sign some locales use.
10
+ const MINUS_SIGN = "\u2212";
11
+ const SPACES = /\s/g;
12
+ /** The decimal and group separators of a locale. */
13
+ export function getNumberSymbols(locale = DEFAULT_NUMBER_LOCALE) {
14
+ let symbols = symbolsByLocale.get(locale);
15
+ if (!symbols) {
16
+ const parts = new Intl.NumberFormat(locale).formatToParts(1234567.5);
17
+ symbols = {
18
+ decimal: parts.find(part => part.type === "decimal")?.value ?? ".",
19
+ group: parts.find(part => part.type === "group")?.value ?? ",",
20
+ };
21
+ symbolsByLocale.set(locale, symbols);
22
+ }
23
+ return symbols;
24
+ }
25
+ /**
26
+ * Formats a number for display: `formatNumber(1250, { decimals: 2, fixedDecimals: true, grouping: true })` gives "1,250.00".
27
+ * Returns "" for `null`, `undefined`, and `NaN`. Digits are always 0–9, and the minus sign is "-", so the text can be typed back.
28
+ */
29
+ export function formatNumber(value, options = {}) {
30
+ if (value === null || value === undefined || !Number.isFinite(value))
31
+ return "";
32
+ const { decimals, fixedDecimals = false, grouping = false, locale = DEFAULT_NUMBER_LOCALE } = options;
33
+ const maxDecimals = decimals ?? MAX_NUMBER_DIGITS;
34
+ const minDecimals = fixedDecimals ? maxDecimals : 0;
35
+ const key = `${locale}|${minDecimals}|${maxDecimals}|${grouping}`;
36
+ let formatter = formatters.get(key);
37
+ if (!formatter) {
38
+ formatter = new Intl.NumberFormat(locale, {
39
+ numberingSystem: "latn",
40
+ useGrouping: grouping,
41
+ minimumFractionDigits: minDecimals,
42
+ maximumFractionDigits: maxDecimals,
43
+ });
44
+ formatters.set(key, formatter);
45
+ }
46
+ // Rounded first, the same way as roundDecimal, which also turns -0.001 into 0 rather than "-0".
47
+ return formatter.format(roundDecimal(value, maxDecimals)).replace(BIDI_MARKS, "").replace(MINUS_SIGN, "-");
48
+ }
49
+ /**
50
+ * Reads a number written in the locale's format: "1,250.50" gives 1250.5, and in `de-DE` "1.250,50" does.
51
+ * Returns `null` for empty text (also a lone minus sign or decimal separator) and `NaN` for text that is not a number.
52
+ */
53
+ export function parseNumber(text, locale = DEFAULT_NUMBER_LOCALE) {
54
+ const { decimal, group } = getNumberSymbols(locale);
55
+ let clean = (text ?? "").replace(BIDI_MARKS, "").replace(SPACES, "").replace(MINUS_SIGN, "-");
56
+ if (group.trim())
57
+ clean = clean.replaceAll(group, "");
58
+ if (decimal !== ".")
59
+ clean = clean.replace(decimal, ".");
60
+ if (/^-?\.?$/.test(clean))
61
+ return null;
62
+ if (!/^-?(?:\d+\.?\d*|\.\d+)$/.test(clean))
63
+ return Number.NaN;
64
+ return Number(clean) || 0;
65
+ }
66
+ /** Counts the digits in text, to keep numbers within `MAX_NUMBER_DIGITS`. */
67
+ export function countDigits(text) {
68
+ let count = 0;
69
+ for (const char of text)
70
+ if (char >= "0" && char <= "9")
71
+ count++;
72
+ return count;
73
+ }
74
+ /**
75
+ * Whether text typed so far can become a valid number: "", "-", "12.", and ".5" can; "1.2.3" and "12a" cannot.
76
+ * The text is edit text: digits, at most one decimal separator, and a leading minus sign, with no group separators.
77
+ */
78
+ export function isPartialNumber(text, decimal, rules) {
79
+ let index = 0;
80
+ if (text.startsWith("-")) {
81
+ if (!rules.negative)
82
+ return false;
83
+ index = 1;
84
+ }
85
+ let digits = 0;
86
+ let fraction = -1;
87
+ for (; index < text.length; index++) {
88
+ const char = text.charAt(index);
89
+ if (char >= "0" && char <= "9") {
90
+ digits++;
91
+ if (fraction >= 0)
92
+ fraction++;
93
+ }
94
+ else if (char === decimal && fraction < 0 && rules.decimals !== 0) {
95
+ fraction = 0;
96
+ }
97
+ else {
98
+ return false;
99
+ }
100
+ }
101
+ return digits <= MAX_NUMBER_DIGITS && (rules.decimals === undefined || fraction <= rules.decimals);
102
+ }
103
+ /**
104
+ * Removes what cannot be part of a number from text that reached the field unchecked (an input method, autofill, a drop),
105
+ * keeping the caret where it was relative to the text that stays. Digits are never removed.
106
+ */
107
+ export function cleanNumberText(text, caret, decimal, rules) {
108
+ let output = "";
109
+ let nextCaret = caret;
110
+ let hasDecimal = false;
111
+ for (let index = 0; index < text.length; index++) {
112
+ const char = text.charAt(index) === MINUS_SIGN ? "-" : text.charAt(index);
113
+ const keep = (char >= "0" && char <= "9") ||
114
+ (char === "-" && output === "" && rules.negative) ||
115
+ (char === decimal && !hasDecimal && rules.decimals !== 0);
116
+ if (keep) {
117
+ output += char;
118
+ if (char === decimal)
119
+ hasDecimal = true;
120
+ }
121
+ else if (index < caret) {
122
+ nextCaret--;
123
+ }
124
+ }
125
+ return { text: output, caret: nextCaret };
126
+ }
127
+ /**
128
+ * Takes the number out of pasted text, such as "Rs 1,250.50", "1 250,50 €", or "-12%", and returns it as edit text
129
+ * ("1250.50"). Returns `null` when the text holds no single clear number, so a paste never turns into a wrong value.
130
+ */
131
+ export function readPastedNumber(text, locale = DEFAULT_NUMBER_LOCALE) {
132
+ const { decimal, group } = getNumberSymbols(locale);
133
+ let clean = text.replace(BIDI_MARKS, "").replace(SPACES, "").replaceAll(MINUS_SIGN, "-");
134
+ if (group.trim())
135
+ clean = clean.replaceAll(group, "");
136
+ const first = clean.search(/\d/);
137
+ if (first < 0)
138
+ return null;
139
+ let start = first;
140
+ // A decimal separator before the first digit belongs to the number (".5"), unless it ends a word ("Rs.1250").
141
+ if (clean[start - 1] === decimal && !/[\p{L}.]/u.test(clean[start - 2] ?? ""))
142
+ start--;
143
+ if (clean[start - 1] === "-")
144
+ start--;
145
+ const last = clean.search(/\d\D*$/) + 1;
146
+ const number = clean.slice(start, last);
147
+ const valid = new RegExp(`^-?(?:\\d+(?:${escapeRegExp(decimal)}\\d*)?|${escapeRegExp(decimal)}\\d+)$`);
148
+ return valid.test(number) ? number : null;
149
+ }
150
+ /**
151
+ * Rounds to a number of decimal places the way people do: 1.005 → 1.01, and -2.5 → -3.
152
+ * Works on the number's shortest decimal text, so binary fractions such as 1.005 (stored as 1.00499…) round up.
153
+ */
154
+ export function roundDecimal(value, digits) {
155
+ if (!Number.isFinite(value))
156
+ return value;
157
+ const [mantissa, exponent = "0"] = String(Math.abs(value)).split("e");
158
+ const shifted = Math.round(Number(`${mantissa}e${Number(exponent) + digits}`));
159
+ const rounded = Number(`${shifted}e${Number(exponent) - digits}`);
160
+ if (Number.isNaN(rounded))
161
+ return value;
162
+ return (value < 0 ? -rounded : rounded) || 0;
163
+ }
164
+ /** Keeps a value within `min` and `max`, each optional. */
165
+ export function clampNumber(value, min, max) {
166
+ if (min !== undefined && value < min)
167
+ return min;
168
+ if (max !== undefined && value > max)
169
+ return max;
170
+ return value;
171
+ }
172
+ /** Digits after the decimal point of a number: 0.25 → 2, 1e-7 → 7. */
173
+ export function countDecimals(value) {
174
+ const match = /(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(value));
175
+ return Math.max(0, (match?.[1]?.length ?? 0) - Number(match?.[2] ?? 0));
176
+ }
177
+ /**
178
+ * The next value for an arrow key or a +/− button. Values move along the grid of `step` from `min` (or 0), so 2.3 with
179
+ * step 1 goes up to 3, and stay within `min` and `max`. An empty field starts at 0, or at the limit nearest to 0.
180
+ */
181
+ export function stepNumber(value, direction, options = {}) {
182
+ const { min, max, decimals } = options;
183
+ const size = Math.abs(options.step ?? 1) || 1;
184
+ if (value === null || Number.isNaN(value)) {
185
+ const start = clampNumber(0, min, max);
186
+ if (start !== 0)
187
+ return start;
188
+ value = 0;
189
+ }
190
+ const base = min ?? 0;
191
+ const precision = Math.max(countDecimals(size), countDecimals(value), countDecimals(base));
192
+ // Rounded first, so float noise (0.30000000000000004 steps) does not skip or repeat a step.
193
+ const offset = roundDecimal((value - base) / size, 9);
194
+ const index = direction > 0 ? Math.floor(offset) + 1 : Math.ceil(offset) - 1;
195
+ let next = clampNumber(roundDecimal(base + index * size, precision), min, max);
196
+ if (decimals !== undefined)
197
+ next = roundDecimal(next, decimals);
198
+ return next;
199
+ }
200
+ function escapeRegExp(text) {
201
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
202
+ }
@@ -0,0 +1,62 @@
1
+ import type { ApiEndpoint, ApiModuleValue } from "../Interfaces/ApiInterfaces.ts";
2
+ /** An app's permission rules. Subclasses answer `can`, and call `changed()` when the user's rights change. */
3
+ export declare abstract class Permissions {
4
+ /** Whether the user may call this endpoint. */
5
+ abstract can(endpoint: ApiEndpoint): boolean;
6
+ /** Whether the rules are known yet. While they load, components show placeholders rather than "not allowed". */
7
+ get ready(): boolean;
8
+ /** Tells the page the rules changed (a sign-in, another branch), so buttons and lists show or hide. */
9
+ protected changed(): void;
10
+ }
11
+ /** Everyone may do everything. The rules until an app registers its own. */
12
+ export declare class AllowAllPermissions extends Permissions {
13
+ can(): boolean;
14
+ }
15
+ /** One action a Nexus user may call, as the backend sends them (`AccessActions`, or the layout's `accessActions`). */
16
+ export interface NexusAccessAction {
17
+ controllerName: string;
18
+ actionName: string;
19
+ /** The backend's `EHttpMethods` number (Get 0, Put 1, Delete 2, Post 3, Patch 6), or the method's name. */
20
+ httpMethod: number | string;
21
+ /** The modules the action belongs to: `NexusModule` flags, combined. */
22
+ modules: number;
23
+ }
24
+ /**
25
+ * The controller and the action of an endpoint's path, as a Nexus backend names them: "Room/Detail/{id}" is the
26
+ * `Detail` action of the `Room` controller. Values in braces are left out.
27
+ */
28
+ export declare function endpointAction(path: string): {
29
+ controller: string;
30
+ action: string;
31
+ };
32
+ /**
33
+ * The Nexus rules: the user may call an endpoint when their access actions hold its controller, action, and method,
34
+ * for its module. Endpoints of the app's own routes (`NexusModule.None`) are always allowed.
35
+ *
36
+ * @example
37
+ * const permissions = definePermissions(new NexusPermissions());
38
+ * permissions.setActions(layout.accessActions); // after sign-in, from the backend
39
+ */
40
+ export declare class NexusPermissions extends Permissions {
41
+ private actions;
42
+ /** `actions`: the user's access actions, or `null` while they load. */
43
+ constructor(actions?: readonly NexusAccessAction[] | null);
44
+ get ready(): boolean;
45
+ /** Replaces the user's access actions, such as after sign-in or a switch of branch. `null`: not known yet. */
46
+ setActions(actions: readonly NexusAccessAction[] | null): void;
47
+ private index;
48
+ can(endpoint: ApiEndpoint<ApiModuleValue>): boolean;
49
+ }
50
+ /**
51
+ * Registers the app's permission rules, once, in a module the root layout loads (the same place as its API modules).
52
+ * Returns them, so the app can keep a handle to update them after sign-in.
53
+ */
54
+ export declare function definePermissions<T extends Permissions>(permissions: T): T;
55
+ /** The app's permission rules: the registered ones, or `AllowAllPermissions`. */
56
+ export declare function getPermissions(): Permissions;
57
+ /** Whether the user may call this endpoint, by the app's rules. */
58
+ export declare function canCall(endpoint: ApiEndpoint | null | undefined): boolean;
59
+ /** For `useSyncExternalStore`: listens for new rules or changed rights. */
60
+ export declare function subscribePermissions(listener: () => void): () => void;
61
+ /** For `useSyncExternalStore`: a number that changes whenever the rules do. */
62
+ export declare const permissionsVersion: () => number;
@@ -0,0 +1,133 @@
1
+ /*
2
+ * Permissions: may the user call this endpoint? Components ask before they show a button or a list (the CRUD's Add,
3
+ * Delete, and its Trash list), so a user sees only what they may do; the server still checks every call.
4
+ *
5
+ * `Permissions` is the interface an app implements, for its own backend's rules; `NexusPermissions` reads the Nexus
6
+ * backend's access actions. Register one with `definePermissions`. Until then everything is allowed, which suits an
7
+ * app without sign-in.
8
+ */
9
+ /** An app's permission rules. Subclasses answer `can`, and call `changed()` when the user's rights change. */
10
+ export class Permissions {
11
+ /** Whether the rules are known yet. While they load, components show placeholders rather than "not allowed". */
12
+ get ready() {
13
+ return true;
14
+ }
15
+ /** Tells the page the rules changed (a sign-in, another branch), so buttons and lists show or hide. */
16
+ changed() {
17
+ if (current === this)
18
+ notify();
19
+ }
20
+ }
21
+ /** Everyone may do everything. The rules until an app registers its own. */
22
+ export class AllowAllPermissions extends Permissions {
23
+ can() {
24
+ return true;
25
+ }
26
+ }
27
+ const NEXUS_METHODS = { GET: 0, PUT: 1, DELETE: 2, POST: 3, PATCH: 6 };
28
+ function methodName(method) {
29
+ if (typeof method === "string")
30
+ return method.toUpperCase();
31
+ return Object.keys(NEXUS_METHODS).find(name => NEXUS_METHODS[name] === method);
32
+ }
33
+ /**
34
+ * The controller and the action of an endpoint's path, as a Nexus backend names them: "Room/Detail/{id}" is the
35
+ * `Detail` action of the `Room` controller. Values in braces are left out.
36
+ */
37
+ export function endpointAction(path) {
38
+ const parts = path.split("/").filter(part => part && !part.startsWith("{"));
39
+ const action = parts.pop() ?? "";
40
+ return { controller: parts.join("/"), action };
41
+ }
42
+ const actionKey = (controller, action, method) => `${controller.toLowerCase()}|${action.toLowerCase()}|${method}`;
43
+ /**
44
+ * The Nexus rules: the user may call an endpoint when their access actions hold its controller, action, and method,
45
+ * for its module. Endpoints of the app's own routes (`NexusModule.None`) are always allowed.
46
+ *
47
+ * @example
48
+ * const permissions = definePermissions(new NexusPermissions());
49
+ * permissions.setActions(layout.accessActions); // after sign-in, from the backend
50
+ */
51
+ export class NexusPermissions extends Permissions {
52
+ actions = null;
53
+ /** `actions`: the user's access actions, or `null` while they load. */
54
+ constructor(actions = null) {
55
+ super();
56
+ if (actions)
57
+ this.index(actions);
58
+ }
59
+ get ready() {
60
+ return this.actions !== null;
61
+ }
62
+ /** Replaces the user's access actions, such as after sign-in or a switch of branch. `null`: not known yet. */
63
+ setActions(actions) {
64
+ if (actions)
65
+ this.index(actions);
66
+ else
67
+ this.actions = null;
68
+ this.changed();
69
+ }
70
+ index(actions) {
71
+ const map = new Map();
72
+ for (const item of actions) {
73
+ const method = methodName(item.httpMethod);
74
+ if (!method || !item.controllerName || !item.actionName)
75
+ continue;
76
+ const key = actionKey(item.controllerName, item.actionName, method);
77
+ const list = map.get(key);
78
+ if (list)
79
+ list.push(Number(item.modules) || 0);
80
+ else
81
+ map.set(key, [Number(item.modules) || 0]);
82
+ }
83
+ this.actions = map;
84
+ }
85
+ // Any module value, whichever type the app registers: a number is read as flags, text as it is.
86
+ can(endpoint) {
87
+ if (endpoint.module === 0)
88
+ return true;
89
+ if (!this.actions)
90
+ return false;
91
+ const { controller, action } = endpointAction(endpoint.path);
92
+ const modules = this.actions.get(actionKey(controller, action, endpoint.method));
93
+ if (!modules)
94
+ return false;
95
+ const module = endpoint.module;
96
+ // An action's modules are flags: it belongs to every module whose bit is set.
97
+ return modules.some(flags => (typeof module === "number" ? (flags & module) === module : String(flags) === String(module)));
98
+ }
99
+ }
100
+ let current = new AllowAllPermissions();
101
+ let version = 0;
102
+ const listeners = new Set();
103
+ function notify() {
104
+ version++;
105
+ for (const listener of listeners)
106
+ listener();
107
+ }
108
+ /**
109
+ * Registers the app's permission rules, once, in a module the root layout loads (the same place as its API modules).
110
+ * Returns them, so the app can keep a handle to update them after sign-in.
111
+ */
112
+ export function definePermissions(permissions) {
113
+ current = permissions;
114
+ notify();
115
+ return permissions;
116
+ }
117
+ /** The app's permission rules: the registered ones, or `AllowAllPermissions`. */
118
+ export function getPermissions() {
119
+ return current;
120
+ }
121
+ /** Whether the user may call this endpoint, by the app's rules. */
122
+ export function canCall(endpoint) {
123
+ return Boolean(endpoint) && current.can(endpoint);
124
+ }
125
+ /** For `useSyncExternalStore`: listens for new rules or changed rights. */
126
+ export function subscribePermissions(listener) {
127
+ listeners.add(listener);
128
+ return () => {
129
+ listeners.delete(listener);
130
+ };
131
+ }
132
+ /** For `useSyncExternalStore`: a number that changes whenever the rules do. */
133
+ export const permissionsVersion = () => version;
@@ -0,0 +1,68 @@
1
+ /** Which side of its anchor a panel opened on: `below` carries its arrow on its top edge, `above` on its bottom edge. */
2
+ export type PanelSide = "below" | "above";
3
+ export type PopoverAlign = "start" | "end";
4
+ export interface PlaceUnderAnchorOptions {
5
+ /** Which edge of the anchor the panel lines up with. Default `start` (the left edge). */
6
+ align?: PopoverAlign;
7
+ /** Space between the anchor and the panel, in pixels. Default 4, or the arrow's reach while it is drawn. */
8
+ gap?: number;
9
+ /** Space kept from the window's edges, in pixels. Default 8. */
10
+ margin?: number;
11
+ /**
12
+ * Draws an arrow on the panel's edge, aimed at the middle of the anchor. Default true: a panel opened from a button
13
+ * says which button. Pass false for a panel that opens flush under a field and is read as part of it.
14
+ */
15
+ arrow?: boolean;
16
+ /**
17
+ * What the arrow points at, when the panel lines up with more than that: the half of a split button that opened it.
18
+ * Default: the anchor itself.
19
+ */
20
+ arrowAt?: DOMRect;
21
+ }
22
+ /**
23
+ * Places a panel under an anchor, or above it when there is no room below, aligned to the anchor's start or end
24
+ * edge and kept inside the window, with an arrow aimed at the anchor. Returns whether the panel went above.
25
+ */
26
+ export declare function placeUnderAnchor(panel: HTMLElement, anchor: DOMRect, options?: PlaceUnderAnchorOptions): boolean;
27
+ export interface PlaceListPanelOptions {
28
+ /** The side of an earlier call, kept while it has `minHeight` of room, so a list that loads more items does not jump across its anchor. */
29
+ side?: PanelSide;
30
+ /** The tallest the panel may be, in pixels. Default 360. */
31
+ maxHeight?: number;
32
+ /** A side is used while at least this much room is there, in pixels; with less, the other side is used when it has more. Default 180. */
33
+ minHeight?: number;
34
+ /** Space between the anchor and the panel, in pixels. Default 4. */
35
+ gap?: number;
36
+ /** Space kept from the window's edges, in pixels. Default 8. */
37
+ margin?: number;
38
+ }
39
+ /**
40
+ * Places a list panel under its anchor, at least as wide as the anchor, or above it when the room below is short and
41
+ * there is more above. The panel's height is capped to the room on its side, so a long list scrolls inside the window
42
+ * instead of running past it. Returns the side, to pass back while the panel stays open.
43
+ *
44
+ * It draws no arrow: the panel is as wide as the field and sits flush under it, so it is already read as that field's
45
+ * list, and an arrow over a field's own border would look like a fault.
46
+ */
47
+ export declare function placeListPanel(panel: HTMLElement, anchor: DOMRect, options?: PlaceListPanelOptions): PanelSide;
48
+ export interface PlaceAtPointOptions {
49
+ /** Space kept from the window's edges, in pixels. Default 8. */
50
+ margin?: number;
51
+ /**
52
+ * Draws an arrow with its tip on the point, so the menu says where it was opened. Default true. The panel then
53
+ * stands the arrow's reach away from the point, and its corner no longer sits on it.
54
+ */
55
+ arrow?: boolean;
56
+ }
57
+ /**
58
+ * Places a panel at a point, such as where the user right-clicked: to the right of and below the point when there
59
+ * is room, otherwise to the left of or above it, and never past the window's edges. With an arrow, the panel is set
60
+ * back far enough along both axes for the arrow's tip to land on the point.
61
+ */
62
+ export declare function placeAtPoint(panel: HTMLElement, x: number, y: number, options?: PlaceAtPointOptions): void;
63
+ /** Runs `place` again, once per frame at most, while the page scrolls or the window changes size. Returns the stop function. */
64
+ export declare function followAnchor(place: () => void): () => void;
65
+ /** Whether the popover is shown. Safe on browsers without popover support, where it is never "open". */
66
+ export declare function isPopoverOpen(panel: HTMLElement | null): boolean;
67
+ /** How far the arrow reaches past the panel's edge: its depth, less the panel's border it is drawn over. */
68
+ export declare const ARROW_REACH: number;
@@ -0,0 +1,195 @@
1
+ /*
2
+ * Placing native popovers. A panel is a fixed [popover] element; these helpers set its top and left once it is shown,
3
+ * keep it inside the window, and move it again while the page scrolls. They measure offsetWidth and offsetHeight,
4
+ * which ignore the panel's opening transform.
5
+ *
6
+ * A panel that belongs to a button or to a place also gets an arrow, so the panel is read as that button's panel and
7
+ * not as a dialog from nowhere. These helpers work out where the arrow goes, because they are the only code that
8
+ * knows both rectangles; `.nx-popover` draws it from what they write (see "The arrow" below).
9
+ */
10
+ /**
11
+ * Places a panel under an anchor, or above it when there is no room below, aligned to the anchor's start or end
12
+ * edge and kept inside the window, with an arrow aimed at the anchor. Returns whether the panel went above.
13
+ */
14
+ export function placeUnderAnchor(panel, anchor, options = {}) {
15
+ const { align = "start", margin = 8, arrow = true } = options;
16
+ // The arrow needs its reach between the panel and the anchor, or it would be drawn over the anchor.
17
+ const gap = Math.max(options.gap ?? 4, arrow ? ARROW_REACH : 0);
18
+ const width = panel.offsetWidth;
19
+ const height = panel.offsetHeight;
20
+ const below = anchor.bottom + gap;
21
+ const above = anchor.top - gap - height;
22
+ const fitsBelow = below + height <= window.innerHeight - margin;
23
+ const top = fitsBelow || above < margin ? below : above;
24
+ const wanted = align === "end" ? anchor.right - width : anchor.left;
25
+ // The arrow points at the middle of what it belongs to. The panel's own style is read once: this runs again on
26
+ // every animation frame while the page scrolls under an open panel.
27
+ const target = options.arrowAt ?? anchor;
28
+ const middle = (target.left + target.right) / 2;
29
+ const style = getComputedStyle(panel);
30
+ const left = Math.max(margin, Math.min(arrow ? centred(panel, target, wanted, width, middle, style) : wanted, window.innerWidth - width - margin));
31
+ panel.style.top = `${Math.round(top)}px`;
32
+ panel.style.left = `${Math.round(left)}px`;
33
+ const side = top === below ? "below" : "above";
34
+ const box = { left: Math.round(left), top: Math.round(top), width, height };
35
+ aimArrow(panel, side, box, arrow ? { at: middle, facing: side === "below" ? target.bottom : target.top, room: gap } : null, style);
36
+ return side === "above";
37
+ }
38
+ /**
39
+ * Places a list panel under its anchor, at least as wide as the anchor, or above it when the room below is short and
40
+ * there is more above. The panel's height is capped to the room on its side, so a long list scrolls inside the window
41
+ * instead of running past it. Returns the side, to pass back while the panel stays open.
42
+ *
43
+ * It draws no arrow: the panel is as wide as the field and sits flush under it, so it is already read as that field's
44
+ * list, and an arrow over a field's own border would look like a fault.
45
+ */
46
+ export function placeListPanel(panel, anchor, options = {}) {
47
+ const { maxHeight = 360, minHeight = 180, gap = 4, margin = 8 } = options;
48
+ const roomBelow = window.innerHeight - anchor.bottom - gap - margin;
49
+ const roomAbove = anchor.top - gap - margin;
50
+ const enough = Math.min(minHeight, maxHeight);
51
+ let side = options.side ?? (roomBelow >= enough || roomBelow >= roomAbove ? "below" : "above");
52
+ // An earlier side is kept while it has room. When the anchor grows (chips wrapping in a dropdown's box) or the page
53
+ // moves until that side has less than minHeight, and the other side has more, the panel moves across instead of
54
+ // shrinking to nothing.
55
+ const room = side === "below" ? roomBelow : roomAbove;
56
+ const otherRoom = side === "below" ? roomAbove : roomBelow;
57
+ if (room < enough && otherRoom > room)
58
+ side = side === "below" ? "above" : "below";
59
+ // Runs after every render of an open list: styles are written only when they change.
60
+ setStyle(panel, "minWidth", `${Math.round(Math.min(anchor.width, window.innerWidth - 2 * margin))}px`);
61
+ setStyle(panel, "maxHeight", `${Math.max(0, Math.floor(Math.min(maxHeight, side === "below" ? roomBelow : roomAbove)))}px`);
62
+ const width = panel.offsetWidth;
63
+ const height = panel.offsetHeight;
64
+ const top = side === "below" ? anchor.bottom + gap : anchor.top - gap - height;
65
+ const left = Math.max(margin, Math.min(anchor.left, window.innerWidth - width - margin));
66
+ setStyle(panel, "top", `${Math.round(top)}px`);
67
+ setStyle(panel, "left", `${Math.round(left)}px`);
68
+ return side;
69
+ }
70
+ function setStyle(element, property, value) {
71
+ if (element.style[property] !== value)
72
+ element.style[property] = value;
73
+ }
74
+ /**
75
+ * Places a panel at a point, such as where the user right-clicked: to the right of and below the point when there
76
+ * is room, otherwise to the left of or above it, and never past the window's edges. With an arrow, the panel is set
77
+ * back far enough along both axes for the arrow's tip to land on the point.
78
+ */
79
+ export function placeAtPoint(panel, x, y, options = {}) {
80
+ const { margin = 8, arrow = true } = options;
81
+ const width = panel.offsetWidth;
82
+ const height = panel.offsetHeight;
83
+ // The tip sits `lead` along the panel's edge and `ARROW_REACH` out from it, so the panel starts that much back.
84
+ const lead = arrow ? arrowLead(panel) : 0;
85
+ const reach = arrow ? ARROW_REACH : 0;
86
+ let left = x - lead;
87
+ let top = y + reach;
88
+ if (left + width > window.innerWidth - margin)
89
+ left = x + lead - width;
90
+ if (top + height > window.innerHeight - margin)
91
+ top = y - reach - height;
92
+ const placed = {
93
+ left: Math.round(Math.max(margin, Math.min(left, window.innerWidth - width - margin))),
94
+ top: Math.round(Math.max(margin, Math.min(top, window.innerHeight - height - margin))),
95
+ width,
96
+ height,
97
+ };
98
+ panel.style.left = `${placed.left}px`;
99
+ panel.style.top = `${placed.top}px`;
100
+ const side = placed.top >= y ? "below" : "above";
101
+ aimArrow(panel, side, placed, arrow ? { at: x, facing: y, room: reach } : null);
102
+ }
103
+ /** Runs `place` again, once per frame at most, while the page scrolls or the window changes size. Returns the stop function. */
104
+ export function followAnchor(place) {
105
+ let frame = 0;
106
+ const reposition = () => {
107
+ cancelAnimationFrame(frame);
108
+ frame = requestAnimationFrame(place);
109
+ };
110
+ window.addEventListener("scroll", reposition, { capture: true, passive: true });
111
+ window.addEventListener("resize", reposition);
112
+ return () => {
113
+ cancelAnimationFrame(frame);
114
+ window.removeEventListener("scroll", reposition, { capture: true });
115
+ window.removeEventListener("resize", reposition);
116
+ };
117
+ }
118
+ /** Whether the popover is shown. Safe on browsers without popover support, where it is never "open". */
119
+ export function isPopoverOpen(panel) {
120
+ return Boolean(panel && typeof panel.matches === "function" && panel.matches(":popover-open"));
121
+ }
122
+ /* ---------------------------------------------------------------------------------------------------------------
123
+ * The arrow
124
+ *
125
+ * An isosceles tail on the panel's edge, drawn in the panel's own border and background, so the two read as one
126
+ * shape in every theme: `.nx-popover[data-nx-arrow]::before` and `::after` in Nexus.Theme.Picker.css. These
127
+ * functions write the two things only the placement knows: which edge carries the tail (`data-nx-arrow`) and where
128
+ * along that edge its tip sits (`--nx-popover-arrow-x`). Both are cleared when it would point at nothing, and no
129
+ * component has to take part.
130
+ * ------------------------------------------------------------------------------------------------------------- */
131
+ /** The arrow's base, across the panel's edge. Keep in step with `--nx-popover-arrow` in the `.nx-popover` rule. */
132
+ const ARROW_BASE = 26;
133
+ /** The arrow's depth, out from the panel's edge. Keep in step with `--nx-popover-arrow-depth`. */
134
+ const ARROW_DEPTH = 11;
135
+ /** Half the arrow's base: how far from its tip each foot stands. */
136
+ const ARROW_HALF = ARROW_BASE / 2;
137
+ /** How far the arrow reaches past the panel's edge: its depth, less the panel's border it is drawn over. */
138
+ export const ARROW_REACH = ARROW_DEPTH - 1;
139
+ /**
140
+ * How far along the panel's edge the arrow's tip has to stay: its own half base, the panel's rounded corner, and two
141
+ * pixels more, so a foot never stands on the curve and the tail is never read as a torn-off corner.
142
+ */
143
+ function arrowLead(panel) {
144
+ const style = panel instanceof HTMLElement ? getComputedStyle(panel) : panel;
145
+ return (parseFloat(style.borderTopLeftRadius) || 0) + ARROW_HALF + 2;
146
+ }
147
+ /**
148
+ * Where a panel starts along its edge so that its arrow stands on the middle of the anchor.
149
+ *
150
+ * The tip may not stand on a rounded corner, so it keeps `lead` from each end of the panel. An **icon button** is
151
+ * narrower than two leads, so a panel lined up with it would hold the tip short of its middle: the panel slides
152
+ * along its edge instead, past the end of the button, by half the button's width at most.
153
+ *
154
+ * A **wide anchor keeps its alignment**, whatever the arrow can reach. A menu belongs at the start of the row,
155
+ * the cell, or the field it opened from - sliding it to the middle of a 900px row would move it right across the
156
+ * page - so the arrow aims as far as it can there and is left out when that is more than half a base off, which is
157
+ * what it did before any of this. The window's edges still win over both.
158
+ */
159
+ function centred(panel, anchor, wanted, width, at, style) {
160
+ const lead = arrowLead(style);
161
+ // Only a button too small to be aimed at while the panel lines up with it is worth moving the panel for.
162
+ if (anchor.width >= lead * 2 || width < lead * 2)
163
+ return wanted;
164
+ // The far end carries a pixel more than the lead: `width` is offsetWidth, a whole number, while the panel itself
165
+ // is fractionally wider, which would otherwise leave the foot that much nearer the curve than the lead promises.
166
+ return Math.min(Math.max(wanted, at - width + lead + 1), at - lead);
167
+ }
168
+ /**
169
+ * Aims the panel's arrow, or leaves it out. The tip is kept clear of the panel's rounded corners, and the arrow is
170
+ * left out when it would point at nothing: the target is off the window, the panel is too narrow to carry an arrow
171
+ * clear of its corners, the panel was pushed along its edge until the tip is more than half a base from the target,
172
+ * or it was pushed away from the target across the edge.
173
+ */
174
+ function aimArrow(panel, side, box, aim, drawn = getComputedStyle(panel)) {
175
+ if (aim) {
176
+ const lead = arrowLead(drawn);
177
+ const x = Math.min(Math.max(aim.at - box.left, lead), box.width - lead);
178
+ const edge = side === "below" ? box.top : box.top + box.height;
179
+ const tip = box.left + x;
180
+ const points = box.width >= lead * 2 && Math.abs(tip - aim.at) <= ARROW_HALF && Math.abs(edge - aim.facing) <= aim.room + 1;
181
+ if (points && onScreen(aim.facing, aim.at)) {
182
+ panel.dataset.nxArrow = side;
183
+ // An absolutely placed arrow starts at the panel's padding box, so the border it is drawn over comes off here.
184
+ const inside = x - (parseFloat(drawn.borderLeftWidth) || 0);
185
+ panel.style.setProperty("--nx-popover-arrow-x", `${Math.round(inside * 10) / 10}px`);
186
+ return;
187
+ }
188
+ }
189
+ delete panel.dataset.nxArrow;
190
+ panel.style.removeProperty("--nx-popover-arrow-x");
191
+ }
192
+ /** Whether what the arrow points at is still in the window: a button scrolled out of sight gets no arrow. */
193
+ function onScreen(across, along) {
194
+ return across >= 0 && across <= window.innerHeight && along >= 0 && along <= window.innerWidth;
195
+ }