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,22 @@
1
+ import { type ReactNode } from "react";
2
+ /** A minimized window as the dock shows it. */
3
+ export interface DockedWindow {
4
+ id: string;
5
+ title: ReactNode;
6
+ /** Plain text of the title, for the tooltip. */
7
+ label?: string;
8
+ /** The window's icon; a window icon when left out. */
9
+ icon?: ReactNode;
10
+ /** Brings the window back. */
11
+ restore: () => void;
12
+ /** Asks the window to close; without it the bar has no close button. */
13
+ close?: () => void;
14
+ }
15
+ /** Puts a minimized window on the dock, or updates the one with its id in place. Newest last. */
16
+ export declare function dockWindow(entry: DockedWindow): void;
17
+ /** Takes a window off the dock. */
18
+ export declare function undockWindow(id: string): void;
19
+ /** Whether a dock is on the page, so a window can be minimized and still be found. */
20
+ export declare function useDockReady(): boolean;
21
+ /** The minimized popups, at the bottom right of the page. Rendered by `<PopupHost />`; render it yourself only without a host. */
22
+ export declare function PopupDock(): import("react").JSX.Element | null;
@@ -0,0 +1,121 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { iconAppWindow, iconChevronDown, iconChevronUp, iconX, InlineIcon } from "nexus-icons";
4
+ import { useEffect, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
5
+ import { cx } from "../../Helpers/ClassHelpers.js";
6
+ const EMPTY = [];
7
+ let windows = [];
8
+ let docks = 0;
9
+ const listeners = new Set();
10
+ function emit() {
11
+ for (const listener of listeners)
12
+ listener();
13
+ }
14
+ function subscribe(listener) {
15
+ listeners.add(listener);
16
+ return () => {
17
+ listeners.delete(listener);
18
+ };
19
+ }
20
+ const getWindows = () => windows;
21
+ const getServerWindows = () => EMPTY;
22
+ const getReady = () => docks > 0;
23
+ const getServerReady = () => false;
24
+ /** Puts a minimized window on the dock, or updates the one with its id in place. Newest last. */
25
+ export function dockWindow(entry) {
26
+ const index = windows.findIndex(item => item.id === entry.id);
27
+ windows = index < 0 ? [...windows, entry] : windows.map(item => (item.id === entry.id ? entry : item));
28
+ emit();
29
+ }
30
+ /** Takes a window off the dock. */
31
+ export function undockWindow(id) {
32
+ if (!windows.some(item => item.id === id))
33
+ return;
34
+ windows = windows.filter(item => item.id !== id);
35
+ emit();
36
+ }
37
+ /** Whether a dock is on the page, so a window can be minimized and still be found. */
38
+ export function useDockReady() {
39
+ return useSyncExternalStore(subscribe, getReady, getServerReady);
40
+ }
41
+ /** The minimized popups, at the bottom right of the page. Rendered by `<PopupHost />`; render it yourself only without a host. */
42
+ export function PopupDock() {
43
+ const list = useSyncExternalStore(subscribe, getWindows, getServerWindows);
44
+ const [expanded, setExpanded] = useState(false);
45
+ const rootRef = useRef(null);
46
+ const toggleRef = useRef(null);
47
+ const id = useId();
48
+ const stacked = list.length > 1;
49
+ const open = expanded && stacked;
50
+ useEffect(() => {
51
+ docks++;
52
+ emit();
53
+ return () => {
54
+ docks--;
55
+ emit();
56
+ };
57
+ }, []);
58
+ // Its height, for what else sits at the bottom right: toasts there stack above the dock (--nx-dock-space).
59
+ const hasWindows = list.length > 0;
60
+ useLayoutEffect(() => {
61
+ const root = rootRef.current;
62
+ if (!hasWindows || !root)
63
+ return;
64
+ const style = document.documentElement.style;
65
+ const observer = new ResizeObserver(() => style.setProperty("--nx-dock-space", `${Math.ceil(root.offsetHeight) + 8}px`));
66
+ observer.observe(root);
67
+ return () => {
68
+ observer.disconnect();
69
+ style.removeProperty("--nx-dock-space");
70
+ };
71
+ }, [hasWindows]);
72
+ // A list of one closes by itself, so the next stack starts closed.
73
+ useEffect(() => {
74
+ if (!stacked)
75
+ setExpanded(false);
76
+ }, [stacked]);
77
+ // An open list closes on Esc, or on a press anywhere else.
78
+ useEffect(() => {
79
+ if (!open)
80
+ return;
81
+ function onKeyDown(event) {
82
+ if (event.key !== "Escape" || event.defaultPrevented)
83
+ return;
84
+ const inside = rootRef.current?.contains(document.activeElement) ?? false;
85
+ setExpanded(false);
86
+ if (inside)
87
+ toggleRef.current?.focus();
88
+ }
89
+ function onPointerDown(event) {
90
+ if (!(event.target instanceof Node) || !rootRef.current?.contains(event.target))
91
+ setExpanded(false);
92
+ }
93
+ document.addEventListener("keydown", onKeyDown);
94
+ document.addEventListener("pointerdown", onPointerDown, true);
95
+ return () => {
96
+ document.removeEventListener("keydown", onKeyDown);
97
+ document.removeEventListener("pointerdown", onPointerDown, true);
98
+ };
99
+ }, [open]);
100
+ if (list.length === 0)
101
+ return null;
102
+ const shown = open ? list : list.slice(-1);
103
+ const depth = open ? 0 : Math.min(list.length - 1, 2);
104
+ const listId = `${id}-list`;
105
+ // The cards peeking out behind the newest bar open the list too.
106
+ function onListClick(event) {
107
+ if (event.target === event.currentTarget && depth > 0)
108
+ setExpanded(true);
109
+ }
110
+ return (_jsxs("section", { ref: rootRef, className: cx("nx-dock", stacked && "nx-dock--stacked", open && "nx-dock--open"), "aria-label": "Minimized windows", children: [stacked && (_jsxs("button", { ref: toggleRef, type: "button", className: "nx-dock__toggle", "aria-label": `${list.length} minimized windows`, "aria-expanded": open, "aria-controls": listId, title: open ? "Show only the newest" : "Show all minimized windows", onClick: () => setExpanded(!open), children: [_jsx("span", { className: "nx-dock__count", children: list.length }), _jsx("span", { children: "minimized" }), _jsx(InlineIcon, { icon: open ? iconChevronDown : iconChevronUp })] })), _jsx("ul", { id: listId, className: "nx-dock__list", "data-depth": depth || undefined, onClick: onListClick, children: shown.map(item => (_jsx(DockBar, { item: item, onRestore: () => setExpanded(false) }, item.id))) })] }));
111
+ }
112
+ // A restored window closes the list, as a taskbar's previews close after a pick.
113
+ function DockBar({ item, onRestore }) {
114
+ const id = useId();
115
+ const titleId = `${id}-title`;
116
+ const closeId = `${id}-close`;
117
+ return (_jsxs("li", { className: "nx-dock__item", children: [_jsxs("button", { type: "button", className: "nx-dock__window", title: item.label ? `Restore: ${item.label}` : "Restore", onClick: () => {
118
+ onRestore();
119
+ item.restore();
120
+ }, children: [_jsx("span", { className: "nx-dock__icon", "aria-hidden": "true", children: item.icon ?? _jsx(InlineIcon, { icon: iconAppWindow }) }), _jsx("span", { className: "nx-visually-hidden", children: "Restore " }), _jsx("span", { id: titleId, className: "nx-dock__title", children: item.title }), _jsx(InlineIcon, { className: "nx-dock__restore", icon: iconChevronUp })] }), item.close && (_jsxs("button", { type: "button", className: "nx-dock__close", "aria-labelledby": `${closeId} ${titleId}`, title: "Close", onClick: item.close, children: [_jsx("span", { id: closeId, hidden: true, children: "Close" }), _jsx(InlineIcon, { icon: iconX })] }))] }));
121
+ }
@@ -0,0 +1,56 @@
1
+ import { type ReactNode } from "react";
2
+ import { type PopupCloseReason, type PopupProps, type PopupWindowState } from "./Popup.tsx";
3
+ export interface PopupHandle {
4
+ readonly id: string;
5
+ /** Closes the popup. */
6
+ close: (reason?: PopupCloseReason) => void;
7
+ /** Changes the title, content, footer, or any other option while the popup is open. */
8
+ update: (changes: Partial<OpenPopupOptions>) => void;
9
+ /** Puts the popup aside as a bar at the bottom right; the page can be used again. */
10
+ minimize: () => void;
11
+ /** Makes the popup fill the window. */
12
+ maximize: () => void;
13
+ /** Brings a minimized popup back as it was (maximized or not), or a maximized one back to its size. */
14
+ restore: () => void;
15
+ /** The window state now: `normal`, `maximized`, or `minimized`. */
16
+ readonly windowState: PopupWindowState;
17
+ /**
18
+ * Resolves with the reason once the popup has closed: after its exit animation, when the dialog is no longer modal and
19
+ * focus is back on the page, so the code that follows can move focus or remove what the popup was about.
20
+ */
21
+ readonly closed: Promise<PopupCloseReason>;
22
+ }
23
+ export interface OpenPopupOptions extends Omit<PopupProps, "open" | "onClose" | "onClosed" | "children" | "footer" | "windowState"> {
24
+ /** The body. A function receives the handle, so buttons inside can close the popup. */
25
+ content?: ReactNode | ((popup: PopupHandle) => ReactNode);
26
+ /** The footer, right-aligned buttons. A function receives the handle. */
27
+ footer?: ReactNode | ((popup: PopupHandle) => ReactNode);
28
+ /** When the popup closes, with the reason. */
29
+ onClose?: (reason: PopupCloseReason) => void;
30
+ /**
31
+ * Asked when the user closes the popup (its close button, Esc, the backdrop, or its bar on the dock): return `false`,
32
+ * or a promise of it, to keep it open, such as after asking "Discard your changes?". Closing from code does not ask.
33
+ */
34
+ beforeClose?: (reason: PopupCloseReason) => boolean | Promise<boolean>;
35
+ /**
36
+ * One popup per key: opening a key whose popup is still open (or minimized) never opens a second one. By `reopen`,
37
+ * that popup closes (with the reason `replaced`) and a fresh one opens (`replace`, the default: `booking-new` for an
38
+ * Add form), or it comes back as it was and its handle is returned (`restore`: `booking-edit-2048`). Rules set with
39
+ * `definePopupRules` apply by key.
40
+ */
41
+ key?: string;
42
+ }
43
+ /**
44
+ * Opens a popup from code and returns its handle. Needs one `<PopupHost />` on the page. With a `key`, the rules set
45
+ * for it (`definePopupRules`) apply under the options, and a popup with the same key still open is replaced or
46
+ * restored (`reopen`).
47
+ *
48
+ * @example
49
+ * const popup = openPopup({ title: "Room 204", content: <RoomDetails id={204} />, footer: p => <Button onClick={() => p.close()}>Close</Button> });
50
+ * await popup.closed;
51
+ */
52
+ export declare function openPopup(given: OpenPopupOptions): PopupHandle;
53
+ /** Closes every popup opened from code, minimized ones too. */
54
+ export declare function closeAllPopups(): void;
55
+ /** Shows the popups opened with `openPopup`, the message boxes, and the dock of minimized popups. Put one in the root layout. */
56
+ export declare function PopupHost(): import("react").JSX.Element;
@@ -0,0 +1,163 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useLayoutEffect, useSyncExternalStore } from "react";
4
+ import { Popup } from "./Popup.js";
5
+ import { HostedPopupContext } from "./PopupContext.js";
6
+ import { PopupDock } from "./PopupDock.js";
7
+ import { withPopupRule } from "./PopupRules.js";
8
+ const EMPTY = [];
9
+ let entries = [];
10
+ let counter = 0;
11
+ let hosts = 0;
12
+ let warned = false;
13
+ const listeners = new Set();
14
+ function emit() {
15
+ for (const listener of listeners)
16
+ listener();
17
+ }
18
+ function subscribe(listener) {
19
+ listeners.add(listener);
20
+ return () => {
21
+ listeners.delete(listener);
22
+ };
23
+ }
24
+ const getSnapshot = () => entries;
25
+ const getServerSnapshot = () => EMPTY;
26
+ const findEntry = (id) => entries.find(candidate => candidate.id === id);
27
+ // The popups a host has rendered. One closed before that (closed or replaced in the same task that opened it) never
28
+ // showed, so nothing will animate it out.
29
+ const rendered = new Set();
30
+ function closeEntry(id, reason) {
31
+ const entry = findEntry(id);
32
+ if (!entry || !entry.open)
33
+ return;
34
+ entries = entries.map(candidate => (candidate.id === id ? { ...candidate, open: false, reason } : candidate));
35
+ emit();
36
+ entry.options.onClose?.(reason);
37
+ // Without a host, or before it has rendered the popup, nothing animates it out, so it is closed now.
38
+ if (hosts === 0 || !rendered.has(id))
39
+ removeEntry(id);
40
+ }
41
+ // The user asked to close: the popup's `beforeClose` may keep it open. One question at a time per popup.
42
+ const asking = new Set();
43
+ function requestClose(id, reason) {
44
+ const guard = findEntry(id)?.options.beforeClose;
45
+ // "code": the browser closed the dialog itself (a form with method="dialog"); there is nothing left to keep open.
46
+ if (!guard || reason === "code") {
47
+ closeEntry(id, reason);
48
+ return;
49
+ }
50
+ if (asking.has(id))
51
+ return;
52
+ asking.add(id);
53
+ void Promise.resolve()
54
+ .then(() => guard(reason))
55
+ .then(close => {
56
+ if (close !== false)
57
+ closeEntry(id, reason);
58
+ }, () => undefined)
59
+ .finally(() => asking.delete(id));
60
+ }
61
+ function removeEntry(id) {
62
+ const entry = findEntry(id);
63
+ rendered.delete(id);
64
+ entries = entries.filter(candidate => candidate.id !== id);
65
+ emit();
66
+ entry?.resolve(entry.reason ?? "code");
67
+ }
68
+ function setWindowState(id, state) {
69
+ const entry = findEntry(id);
70
+ if (!entry || !entry.open || entry.windowState === state)
71
+ return;
72
+ const restoreTo = entry.windowState === "minimized" ? entry.restoreTo : entry.windowState;
73
+ entries = entries.map(candidate => (candidate.id === id ? { ...candidate, windowState: state, restoreTo } : candidate));
74
+ emit();
75
+ entry.options.onWindowStateChange?.(state);
76
+ }
77
+ function restoreEntry(id) {
78
+ const entry = findEntry(id);
79
+ if (!entry)
80
+ return;
81
+ if (entry.windowState === "minimized")
82
+ setWindowState(id, entry.restoreTo);
83
+ else if (entry.windowState === "maximized")
84
+ setWindowState(id, "normal");
85
+ }
86
+ /**
87
+ * Opens a popup from code and returns its handle. Needs one `<PopupHost />` on the page. With a `key`, the rules set
88
+ * for it (`definePopupRules`) apply under the options, and a popup with the same key still open is replaced or
89
+ * restored (`reopen`).
90
+ *
91
+ * @example
92
+ * const popup = openPopup({ title: "Room 204", content: <RoomDetails id={204} />, footer: p => <Button onClick={() => p.close()}>Close</Button> });
93
+ * await popup.closed;
94
+ */
95
+ export function openPopup(given) {
96
+ const options = withPopupRule(given);
97
+ if (options.key !== undefined) {
98
+ const existing = entries.find(candidate => candidate.open && candidate.options.key === options.key);
99
+ if (existing && options.reopen === "restore") {
100
+ if (existing.windowState === "minimized")
101
+ restoreEntry(existing.id);
102
+ return existing.handle;
103
+ }
104
+ if (existing)
105
+ closeEntry(existing.id, "replaced");
106
+ }
107
+ const id = `nx-popup-${++counter}`;
108
+ let resolve = () => undefined;
109
+ const closed = new Promise(done => {
110
+ resolve = done;
111
+ });
112
+ const handle = {
113
+ id,
114
+ close: (reason = "code") => closeEntry(id, reason),
115
+ update: changes => {
116
+ entries = entries.map(candidate => (candidate.id === id ? { ...candidate, options: { ...candidate.options, ...changes } } : candidate));
117
+ emit();
118
+ },
119
+ minimize: () => setWindowState(id, "minimized"),
120
+ maximize: () => setWindowState(id, "maximized"),
121
+ restore: () => restoreEntry(id),
122
+ get windowState() {
123
+ return findEntry(id)?.windowState ?? "normal";
124
+ },
125
+ closed,
126
+ };
127
+ const initial = options.defaultWindowState ?? "normal";
128
+ entries = [...entries, { id, options, open: true, windowState: initial, restoreTo: initial, handle, resolve }];
129
+ if (hosts === 0 && !warned && typeof window !== "undefined") {
130
+ warned = true;
131
+ console.warn("openPopup(): no <PopupHost /> is mounted, so popups cannot show. Add one to the root layout.");
132
+ }
133
+ emit();
134
+ return handle;
135
+ }
136
+ /** Closes every popup opened from code, minimized ones too. */
137
+ export function closeAllPopups() {
138
+ for (const entry of entries)
139
+ closeEntry(entry.id, "code");
140
+ }
141
+ /** Shows the popups opened with `openPopup`, the message boxes, and the dock of minimized popups. Put one in the root layout. */
142
+ export function PopupHost() {
143
+ const list = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
144
+ useEffect(() => {
145
+ hosts++;
146
+ return () => {
147
+ hosts--;
148
+ // Popups that were closing when the last host went away will never finish their animation.
149
+ if (hosts === 0)
150
+ for (const entry of entries)
151
+ if (!entry.open)
152
+ removeEntry(entry.id);
153
+ };
154
+ }, []);
155
+ useLayoutEffect(() => {
156
+ for (const entry of list)
157
+ rendered.add(entry.id);
158
+ });
159
+ return (_jsxs(HostedPopupContext, { value: true, children: [list.map(entry => {
160
+ const { content, footer, onClose: _onClose, beforeClose: _beforeClose, onWindowStateChange: _onWindowStateChange, key: _key, ...rest } = entry.options;
161
+ return (_jsx(Popup, { ...rest, open: entry.open, windowState: entry.windowState, onWindowStateChange: state => setWindowState(entry.id, state), footer: typeof footer === "function" ? footer(entry.handle) : footer, onClose: reason => requestClose(entry.id, reason), onClosed: () => removeEntry(entry.id), children: typeof content === "function" ? content(entry.handle) : content }, entry.id));
162
+ }), _jsx(PopupDock, {})] }));
163
+ }
@@ -0,0 +1,30 @@
1
+ import type { PopupProps } from "./Popup.tsx";
2
+ /**
3
+ * What a popup's rule may set: `reopen` (`replace` or `restore`), the window buttons and moving (`minimizable`,
4
+ * `maximizable`, `movable`), how it closes (`closable`, `closeOnEscape`, `closeOnBackdrop`), its `size`, and its
5
+ * `defaultWindowState`.
6
+ */
7
+ export type PopupRule = Pick<PopupProps, "reopen" | "minimizable" | "maximizable" | "movable" | "closable" | "closeOnEscape" | "closeOnBackdrop" | "size" | "defaultWindowState">;
8
+ /**
9
+ * Sets rules for popups by key. A name is a key (`booking-new`), or a pattern ending in `*` for every key that starts
10
+ * with the rest (`booking-edit-*`; `*` alone matches every key). Every rule that matches a key applies, the more
11
+ * specific over the less: an exact key over a pattern, a longer pattern over a shorter one. Options given to
12
+ * `openPopup` win over all of them. Setting a name again replaces its rule. Call it in a client module, where the app
13
+ * starts or beside the code that opens the popups. Returns a function that removes these rules.
14
+ *
15
+ * @example
16
+ * definePopupRules({
17
+ * "booking-new": { reopen: "replace" }, // Add: a fresh form every time
18
+ * "booking-edit-*": { reopen: "restore" }, // Edit: back as it was, with what was typed
19
+ * "night-report": { minimizable: false, maximizable: false, movable: false },
20
+ * });
21
+ */
22
+ export declare function definePopupRules(next: Record<string, PopupRule>): () => void;
23
+ /** Removes every rule. */
24
+ export declare function clearPopupRules(): void;
25
+ /** The rule for a key: every matching rule merged, the more specific over the less. Undefined when none matches. */
26
+ export declare function popupRuleFor(key: string | undefined): PopupRule | undefined;
27
+ /** A popup's options over its key's rule: what the options leave out, or set to undefined, comes from the rule. */
28
+ export declare function withPopupRule<T extends {
29
+ key?: string;
30
+ }>(options: T): T & PopupRule;
@@ -0,0 +1,63 @@
1
+ const rules = new Map();
2
+ /**
3
+ * Sets rules for popups by key. A name is a key (`booking-new`), or a pattern ending in `*` for every key that starts
4
+ * with the rest (`booking-edit-*`; `*` alone matches every key). Every rule that matches a key applies, the more
5
+ * specific over the less: an exact key over a pattern, a longer pattern over a shorter one. Options given to
6
+ * `openPopup` win over all of them. Setting a name again replaces its rule. Call it in a client module, where the app
7
+ * starts or beside the code that opens the popups. Returns a function that removes these rules.
8
+ *
9
+ * @example
10
+ * definePopupRules({
11
+ * "booking-new": { reopen: "replace" }, // Add: a fresh form every time
12
+ * "booking-edit-*": { reopen: "restore" }, // Edit: back as it was, with what was typed
13
+ * "night-report": { minimizable: false, maximizable: false, movable: false },
14
+ * });
15
+ */
16
+ export function definePopupRules(next) {
17
+ const added = Object.entries(next);
18
+ for (const [name, rule] of added)
19
+ rules.set(name, rule);
20
+ return () => {
21
+ for (const [name, rule] of added)
22
+ if (rules.get(name) === rule)
23
+ rules.delete(name);
24
+ };
25
+ }
26
+ /** Removes every rule. */
27
+ export function clearPopupRules() {
28
+ rules.clear();
29
+ }
30
+ /** How closely a rule's name matches a key: -1 when it does not; an exact key beats any pattern. */
31
+ function specificity(name, key) {
32
+ if (name === key)
33
+ return Number.MAX_SAFE_INTEGER;
34
+ if (!name.endsWith("*"))
35
+ return -1;
36
+ const prefix = name.slice(0, -1);
37
+ return key.startsWith(prefix) ? prefix.length : -1;
38
+ }
39
+ /** The rule for a key: every matching rule merged, the more specific over the less. Undefined when none matches. */
40
+ export function popupRuleFor(key) {
41
+ if (key === undefined || rules.size === 0)
42
+ return undefined;
43
+ const matches = [...rules]
44
+ .map(([name, rule]) => ({ rule, rank: specificity(name, key) }))
45
+ .filter(match => match.rank >= 0)
46
+ .sort((a, b) => a.rank - b.rank);
47
+ if (matches.length === 0)
48
+ return undefined;
49
+ return matches.reduce((merged, match) => withDefined(merged, match.rule), {});
50
+ }
51
+ /** A popup's options over its key's rule: what the options leave out, or set to undefined, comes from the rule. */
52
+ export function withPopupRule(options) {
53
+ const rule = popupRuleFor(options.key);
54
+ return rule ? withDefined(rule, options) : options;
55
+ }
56
+ // `{ ...base, ...over }`, except that an undefined value in `over` does not hide the one in `base`.
57
+ function withDefined(base, over) {
58
+ const result = { ...base };
59
+ for (const [name, value] of Object.entries(over))
60
+ if (value !== undefined)
61
+ result[name] = value;
62
+ return result;
63
+ }
@@ -0,0 +1,13 @@
1
+ import { type ThemeOption } from "../../Interfaces/ThemeInterfaces.ts";
2
+ export interface ThemePickerProps {
3
+ /** Themes to offer. Default: every built-in theme. */
4
+ themes?: readonly ThemeOption[];
5
+ /** Show the Light / Dark / System choice. Default `true`. */
6
+ showMode?: boolean;
7
+ className?: string;
8
+ }
9
+ /**
10
+ * Light / Dark / System, and a card per theme with a live preview of its colors.
11
+ * The choice applies at once and is saved in the browser.
12
+ */
13
+ export declare function ThemePicker({ themes, showMode, className }: ThemePickerProps): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { iconCheck, iconDeviceDesktop, iconMoon, iconSun, InlineIcon } from "nexus-icons";
4
+ import { useId } from "react";
5
+ import { cx } from "../../Helpers/ClassHelpers.js";
6
+ import { NEXUS_THEMES } from "../../Interfaces/ThemeInterfaces.js";
7
+ import { useTheme } from "../../Services/ThemeService.js";
8
+ import { TabButtons } from "../Documents/TabButtons.js";
9
+ const MODES = [
10
+ { value: "light", label: "Light", icon: _jsx(InlineIcon, { icon: iconSun }) },
11
+ { value: "dark", label: "Dark", icon: _jsx(InlineIcon, { icon: iconMoon }) },
12
+ { value: "system", label: "System", icon: _jsx(InlineIcon, { icon: iconDeviceDesktop }), title: "Follow the operating system" },
13
+ ];
14
+ /**
15
+ * Light / Dark / System, and a card per theme with a live preview of its colors.
16
+ * The choice applies at once and is saved in the browser.
17
+ */
18
+ export function ThemePicker({ themes = NEXUS_THEMES, showMode = true, className }) {
19
+ const { theme, mode, setTheme, setMode } = useTheme();
20
+ const name = useId();
21
+ return (_jsxs("div", { className: cx("nx-theme-picker", className), children: [showMode && (_jsxs("div", { className: "nx-theme-picker__group", children: [_jsx("p", { id: `${name}-mode`, className: "nx-theme-picker__legend", children: "Mode" }), _jsx(TabButtons, { "aria-labelledby": `${name}-mode`, name: `${name}-mode`, options: MODES, value: mode, onChange: setMode, block: true })] })), _jsxs("fieldset", { className: "nx-theme-picker__group", children: [_jsx("legend", { className: "nx-theme-picker__legend", children: "Theme" }), _jsx("div", { className: "nx-theme-picker__grid", children: themes.map(option => (_jsxs("label", { className: "nx-theme-option", title: option.description, children: [_jsx("input", { type: "radio", className: "nx-visually-hidden", name: `${name}-theme`, value: option.id, checked: theme === option.id, onChange: () => setTheme(option.id) }), _jsx("span", { className: "nx-theme-option__preview", "data-nx-theme": option.id, "aria-hidden": "true", children: _jsxs("span", { className: "nx-theme-option__window", children: [_jsx("span", { className: "nx-theme-option__line" }), _jsx("span", { className: "nx-theme-option__line nx-theme-option__line--muted" }), _jsxs("span", { className: "nx-theme-option__swatches", children: [_jsx("span", { className: "nx-theme-option__pill" }), _jsx("span", { className: "nx-theme-option__dot nx-theme-option__dot--success" }), _jsx("span", { className: "nx-theme-option__dot nx-theme-option__dot--warning" }), _jsx("span", { className: "nx-theme-option__dot nx-theme-option__dot--danger" })] })] }) }), _jsxs("span", { className: "nx-theme-option__name", children: [option.name, _jsx(InlineIcon, { icon: iconCheck, className: "nx-theme-option__check" })] })] }, option.id))) })] })] }));
22
+ }
@@ -0,0 +1,14 @@
1
+ import { type ThemeScriptOptions } from "../../Helpers/ThemeHelpers.ts";
2
+ export interface ThemeScriptProps extends ThemeScriptOptions {
3
+ /** Content Security Policy nonce, when the app uses one. */
4
+ nonce?: string;
5
+ }
6
+ /**
7
+ * Applies the saved theme and mode before the first paint. Render it in `<head>` of the root layout,
8
+ * and put `suppressHydrationWarning` on `<html>`, because the script sets attributes there.
9
+ *
10
+ * @example
11
+ * <html lang="en" suppressHydrationWarning>
12
+ * <head><ThemeScript /></head>
13
+ */
14
+ export declare function ThemeScript({ nonce, ...options }: ThemeScriptProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { themeScript } from "../../Helpers/ThemeHelpers.js";
3
+ /**
4
+ * Applies the saved theme and mode before the first paint. Render it in `<head>` of the root layout,
5
+ * and put `suppressHydrationWarning` on `<html>`, because the script sets attributes there.
6
+ *
7
+ * @example
8
+ * <html lang="en" suppressHydrationWarning>
9
+ * <head><ThemeScript /></head>
10
+ */
11
+ export function ThemeScript({ nonce, ...options }) {
12
+ return _jsx("script", { nonce: nonce, dangerouslySetInnerHTML: { __html: themeScript(options) } });
13
+ }
@@ -0,0 +1,13 @@
1
+ import { type ButtonVariant } from "../Documents/Button.tsx";
2
+ import { type ThemePickerProps } from "./ThemePicker.tsx";
3
+ export interface ThemeSwitcherProps extends ThemePickerProps {
4
+ /** Name of the button for screen readers, also shown as its tooltip. Default "Theme". */
5
+ label?: string;
6
+ /** Default `ghost`. */
7
+ variant?: ButtonVariant;
8
+ }
9
+ /**
10
+ * A palette button that opens the theme picker below it, with the panel's arrow on the button. The panel is a native
11
+ * popover: it closes with Esc or a click outside, and needs no library.
12
+ */
13
+ export declare function ThemeSwitcher({ label, variant, className, ...pickerProps }: ThemeSwitcherProps): import("react").JSX.Element;
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { iconPalette, InlineIcon } from "nexus-icons";
4
+ import { useId, useLayoutEffect, useRef, useState } from "react";
5
+ import { followAnchor, isPopoverOpen, placeUnderAnchor } from "../../Helpers/PopoverHelpers.js";
6
+ import { Button } from "../Documents/Button.js";
7
+ import { ThemePicker } from "./ThemePicker.js";
8
+ /**
9
+ * A palette button that opens the theme picker below it, with the panel's arrow on the button. The panel is a native
10
+ * popover: it closes with Esc or a click outside, and needs no library.
11
+ */
12
+ export function ThemeSwitcher({ label = "Theme", variant = "ghost", className, ...pickerProps }) {
13
+ const panelId = useId();
14
+ const buttonRef = useRef(null);
15
+ const panelRef = useRef(null);
16
+ const [open, setOpen] = useState(false);
17
+ // Set on pointer down while the panel is open: that press closes it (light dismiss), and its click must not reopen it.
18
+ const dismissingRef = useRef(false);
19
+ // The panel is shown from here rather than by the button's popovertarget, because it can be measured only once it is
20
+ // shown: placing it needs its size. It opens under the button, lined up with its right edge and inside the window.
21
+ useLayoutEffect(() => {
22
+ const panel = panelRef.current;
23
+ const button = buttonRef.current;
24
+ if (!open || !panel || !button)
25
+ return;
26
+ const place = () => placeUnderAnchor(panel, button.getBoundingClientRect(), { align: "end" });
27
+ place();
28
+ return followAnchor(place);
29
+ }, [open]);
30
+ // Opening sets the state in the click itself, so the panel is placed before the frame it first paints in; closing
31
+ // can also come from Esc or a click outside, which only the event reports.
32
+ function onToggle(event) {
33
+ if (event.newState === "closed")
34
+ setOpen(false);
35
+ }
36
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { ref: buttonRef, variant: variant, className: className, "aria-label": label, title: label, "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": panelId, icon: _jsx(InlineIcon, { icon: iconPalette }), onPointerDown: () => {
37
+ dismissingRef.current = isPopoverOpen(panelRef.current);
38
+ }, onClick: () => {
39
+ const panel = panelRef.current;
40
+ if (dismissingRef.current)
41
+ dismissingRef.current = false;
42
+ else if (isPopoverOpen(panel))
43
+ panel?.hidePopover();
44
+ else if (panel && typeof panel.showPopover === "function") {
45
+ panel.showPopover();
46
+ setOpen(true);
47
+ }
48
+ } }), _jsx("div", { ref: panelRef, id: panelId, popover: "auto", role: "dialog", "aria-label": label, className: "nx-popover nx-theme-switcher__panel", onToggle: onToggle, children: _jsx(ThemePicker, { ...pickerProps }) })] }));
49
+ }