nexus-shared 1.1.20 → 2.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 (332) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +903 -0
  3. package/dist/Client.Index.d.ts +44 -0
  4. package/dist/Client.Index.js +49 -0
  5. package/dist/Components/Documents/Button.d.ts +29 -0
  6. package/dist/Components/Documents/Button.js +11 -0
  7. package/dist/Components/Documents/Menu.d.ts +102 -0
  8. package/dist/Components/Documents/Menu.js +238 -0
  9. package/dist/Components/Documents/SplitButton.d.ts +64 -0
  10. package/dist/Components/Documents/SplitButton.js +127 -0
  11. package/dist/Components/Documents/TabButtons.d.ts +62 -0
  12. package/dist/Components/Documents/TabButtons.js +19 -0
  13. package/dist/Components/Forms/ApiForm.d.ts +21 -0
  14. package/dist/Components/Forms/ApiForm.js +99 -0
  15. package/dist/Components/Forms/Crud.d.ts +17 -0
  16. package/dist/Components/Forms/Crud.js +556 -0
  17. package/dist/Components/Forms/CrudParts.d.ts +15 -0
  18. package/dist/Components/Forms/CrudParts.js +36 -0
  19. package/dist/Components/Forms/Form.d.ts +52 -0
  20. package/dist/Components/Forms/Form.js +319 -0
  21. package/dist/Components/Forms/SubmitForm.d.ts +65 -0
  22. package/dist/Components/Forms/SubmitForm.js +198 -0
  23. package/dist/Components/Inputs/Calendar.d.ts +69 -0
  24. package/dist/Components/Inputs/Calendar.js +258 -0
  25. package/dist/Components/Inputs/CheckBox.d.ts +53 -0
  26. package/dist/Components/Inputs/CheckBox.js +87 -0
  27. package/dist/Components/Inputs/CheckBoxGroup.d.ts +20 -0
  28. package/dist/Components/Inputs/CheckBoxGroup.js +80 -0
  29. package/dist/Components/Inputs/ChoiceField.d.ts +122 -0
  30. package/dist/Components/Inputs/ChoiceField.js +169 -0
  31. package/dist/Components/Inputs/DatePicker.d.ts +54 -0
  32. package/dist/Components/Inputs/DatePicker.js +246 -0
  33. package/dist/Components/Inputs/DateRangePicker.d.ts +62 -0
  34. package/dist/Components/Inputs/DateRangePicker.js +283 -0
  35. package/dist/Components/Inputs/DateTimePicker.d.ts +75 -0
  36. package/dist/Components/Inputs/DateTimePicker.js +399 -0
  37. package/dist/Components/Inputs/Dropdown.d.ts +117 -0
  38. package/dist/Components/Inputs/Dropdown.js +839 -0
  39. package/dist/Components/Inputs/DropdownParts.d.ts +84 -0
  40. package/dist/Components/Inputs/DropdownParts.js +102 -0
  41. package/dist/Components/Inputs/EditorShell.d.ts +45 -0
  42. package/dist/Components/Inputs/EditorShell.js +214 -0
  43. package/dist/Components/Inputs/Field.d.ts +53 -0
  44. package/dist/Components/Inputs/Field.js +16 -0
  45. package/dist/Components/Inputs/GroupForm.d.ts +20 -0
  46. package/dist/Components/Inputs/GroupForm.js +170 -0
  47. package/dist/Components/Inputs/InputField.d.ts +59 -0
  48. package/dist/Components/Inputs/InputField.js +169 -0
  49. package/dist/Components/Inputs/InputRenderer.d.ts +35 -0
  50. package/dist/Components/Inputs/InputRenderer.js +99 -0
  51. package/dist/Components/Inputs/MarkdownEditor.d.ts +67 -0
  52. package/dist/Components/Inputs/MarkdownEditor.js +289 -0
  53. package/dist/Components/Inputs/NumberBox.d.ts +53 -0
  54. package/dist/Components/Inputs/NumberBox.js +228 -0
  55. package/dist/Components/Inputs/RadioGroup.d.ts +20 -0
  56. package/dist/Components/Inputs/RadioGroup.js +43 -0
  57. package/dist/Components/Inputs/ReadOnlyNotice.d.ts +36 -0
  58. package/dist/Components/Inputs/ReadOnlyNotice.js +116 -0
  59. package/dist/Components/Inputs/RichTextEditor.d.ts +103 -0
  60. package/dist/Components/Inputs/RichTextEditor.js +1170 -0
  61. package/dist/Components/Inputs/RichTextParts.d.ts +63 -0
  62. package/dist/Components/Inputs/RichTextParts.js +157 -0
  63. package/dist/Components/Inputs/RowsInput.d.ts +104 -0
  64. package/dist/Components/Inputs/RowsInput.js +259 -0
  65. package/dist/Components/Inputs/Slider.d.ts +87 -0
  66. package/dist/Components/Inputs/Slider.js +216 -0
  67. package/dist/Components/Inputs/TabularForm.d.ts +23 -0
  68. package/dist/Components/Inputs/TabularForm.js +283 -0
  69. package/dist/Components/Inputs/TextArea.d.ts +43 -0
  70. package/dist/Components/Inputs/TextArea.js +31 -0
  71. package/dist/Components/Inputs/TextBox.d.ts +52 -0
  72. package/dist/Components/Inputs/TextBox.js +58 -0
  73. package/dist/Components/Inputs/TextField.d.ts +31 -0
  74. package/dist/Components/Inputs/TextField.js +35 -0
  75. package/dist/Components/Inputs/TimePanel.d.ts +34 -0
  76. package/dist/Components/Inputs/TimePanel.js +288 -0
  77. package/dist/Components/Inputs/TimePicker.d.ts +54 -0
  78. package/dist/Components/Inputs/TimePicker.js +239 -0
  79. package/dist/Components/Inputs/TreeView.d.ts +160 -0
  80. package/dist/Components/Inputs/TreeView.js +947 -0
  81. package/dist/Components/Layouts/MessageBox.d.ts +71 -0
  82. package/dist/Components/Layouts/MessageBox.js +104 -0
  83. package/dist/Components/Layouts/Popup.d.ts +92 -0
  84. package/dist/Components/Layouts/Popup.js +376 -0
  85. package/dist/Components/Layouts/PopupContext.d.ts +2 -0
  86. package/dist/Components/Layouts/PopupContext.js +4 -0
  87. package/dist/Components/Layouts/PopupDock.d.ts +22 -0
  88. package/dist/Components/Layouts/PopupDock.js +121 -0
  89. package/dist/Components/Layouts/PopupHost.d.ts +56 -0
  90. package/dist/Components/Layouts/PopupHost.js +163 -0
  91. package/dist/Components/Layouts/PopupRules.d.ts +30 -0
  92. package/dist/Components/Layouts/PopupRules.js +63 -0
  93. package/dist/Components/Layouts/ThemePicker.d.ts +13 -0
  94. package/dist/Components/Layouts/ThemePicker.js +22 -0
  95. package/dist/Components/Layouts/ThemeScript.d.ts +14 -0
  96. package/dist/Components/Layouts/ThemeScript.js +13 -0
  97. package/dist/Components/Layouts/ThemeSwitcher.d.ts +13 -0
  98. package/dist/Components/Layouts/ThemeSwitcher.js +29 -0
  99. package/dist/Components/Layouts/Toaster.d.ts +76 -0
  100. package/dist/Components/Layouts/Toaster.js +172 -0
  101. package/dist/Components/Viewers/DataTable.d.ts +25 -0
  102. package/dist/Components/Viewers/DataTable.js +542 -0
  103. package/dist/Components/Viewers/DataTableParts.d.ts +134 -0
  104. package/dist/Components/Viewers/DataTableParts.js +145 -0
  105. package/dist/Components/Viewers/MarkdownView.d.ts +26 -0
  106. package/dist/Components/Viewers/MarkdownView.js +79 -0
  107. package/dist/Components/Viewers/RichTextView.d.ts +18 -0
  108. package/dist/Components/Viewers/RichTextView.js +17 -0
  109. package/dist/Helpers/AnimationHelpers.d.ts +6 -0
  110. package/dist/Helpers/AnimationHelpers.js +35 -0
  111. package/dist/Helpers/ApiClient.d.ts +74 -0
  112. package/dist/Helpers/ApiClient.js +197 -0
  113. package/dist/Helpers/ApiFormHelpers.d.ts +26 -0
  114. package/dist/Helpers/ApiFormHelpers.js +56 -0
  115. package/dist/Helpers/ApiModules.d.ts +135 -0
  116. package/dist/Helpers/ApiModules.js +194 -0
  117. package/dist/Helpers/ApiResponses.d.ts +41 -0
  118. package/dist/Helpers/ApiResponses.js +159 -0
  119. package/dist/Helpers/ApiRoutes.d.ts +150 -0
  120. package/dist/Helpers/ApiRoutes.js +191 -0
  121. package/dist/Helpers/ApiToasts.d.ts +21 -0
  122. package/dist/Helpers/ApiToasts.js +22 -0
  123. package/dist/Helpers/ClassHelpers.d.ts +3 -0
  124. package/dist/Helpers/ClassHelpers.js +4 -0
  125. package/dist/Helpers/CrudBackend.d.ts +56 -0
  126. package/dist/Helpers/CrudBackend.js +119 -0
  127. package/dist/Helpers/CrudHelpers.d.ts +76 -0
  128. package/dist/Helpers/CrudHelpers.js +202 -0
  129. package/dist/Helpers/DateHelpers.d.ts +88 -0
  130. package/dist/Helpers/DateHelpers.js +363 -0
  131. package/dist/Helpers/DatePreferences.d.ts +14 -0
  132. package/dist/Helpers/DatePreferences.js +94 -0
  133. package/dist/Helpers/DateTimeHelpers.d.ts +87 -0
  134. package/dist/Helpers/DateTimeHelpers.js +286 -0
  135. package/dist/Helpers/DragHelpers.d.ts +129 -0
  136. package/dist/Helpers/DragHelpers.js +281 -0
  137. package/dist/Helpers/DropdownHelpers.d.ts +56 -0
  138. package/dist/Helpers/DropdownHelpers.js +180 -0
  139. package/dist/Helpers/FormDrafts.d.ts +18 -0
  140. package/dist/Helpers/FormDrafts.js +76 -0
  141. package/dist/Helpers/FormStore.d.ts +231 -0
  142. package/dist/Helpers/FormStore.js +734 -0
  143. package/dist/Helpers/InputParamsHelpers.d.ts +79 -0
  144. package/dist/Helpers/InputParamsHelpers.js +388 -0
  145. package/dist/Helpers/MarkdownEditing.d.ts +27 -0
  146. package/dist/Helpers/MarkdownEditing.js +250 -0
  147. package/dist/Helpers/MarkdownHelpers.d.ts +82 -0
  148. package/dist/Helpers/MarkdownHelpers.js +775 -0
  149. package/dist/Helpers/MessageBuilder.d.ts +74 -0
  150. package/dist/Helpers/MessageBuilder.js +254 -0
  151. package/dist/Helpers/NepaliCalendar.d.ts +25 -0
  152. package/dist/Helpers/NepaliCalendar.js +107 -0
  153. package/dist/Helpers/NumberHelpers.d.ts +71 -0
  154. package/dist/Helpers/NumberHelpers.js +202 -0
  155. package/dist/Helpers/Permissions.d.ts +62 -0
  156. package/dist/Helpers/Permissions.js +133 -0
  157. package/dist/Helpers/PopoverHelpers.d.ts +43 -0
  158. package/dist/Helpers/PopoverHelpers.js +91 -0
  159. package/dist/Helpers/RichTextHelpers.d.ts +77 -0
  160. package/dist/Helpers/RichTextHelpers.js +1072 -0
  161. package/dist/Helpers/RowsStore.d.ts +160 -0
  162. package/dist/Helpers/RowsStore.js +584 -0
  163. package/dist/Helpers/TableColumns.d.ts +40 -0
  164. package/dist/Helpers/TableColumns.js +254 -0
  165. package/dist/Helpers/TableExport.d.ts +30 -0
  166. package/dist/Helpers/TableExport.js +97 -0
  167. package/dist/Helpers/TableHelpers.d.ts +102 -0
  168. package/dist/Helpers/TableHelpers.js +281 -0
  169. package/dist/Helpers/TableStore.d.ts +142 -0
  170. package/dist/Helpers/TableStore.js +530 -0
  171. package/dist/Helpers/ThemeHelpers.d.ts +15 -0
  172. package/dist/Helpers/ThemeHelpers.js +16 -0
  173. package/dist/Helpers/TimeHelpers.d.ts +73 -0
  174. package/dist/Helpers/TimeHelpers.js +253 -0
  175. package/dist/Helpers/TreeStore.d.ts +188 -0
  176. package/dist/Helpers/TreeStore.js +577 -0
  177. package/dist/Helpers/ValidationHelpers.d.ts +124 -0
  178. package/dist/Helpers/ValidationHelpers.js +301 -0
  179. package/dist/Interfaces/ApiInterfaces.d.ts +149 -0
  180. package/dist/Interfaces/ApiInterfaces.js +24 -0
  181. package/dist/Interfaces/CrudInterfaces.d.ts +171 -0
  182. package/{src/sso-client.tsx → dist/Interfaces/CrudInterfaces.js} +1 -1
  183. package/dist/Interfaces/DateInterfaces.d.ts +154 -0
  184. package/dist/Interfaces/DateInterfaces.js +29 -0
  185. package/dist/Interfaces/FormInterfaces.d.ts +352 -0
  186. package/dist/Interfaces/FormInterfaces.js +1 -0
  187. package/dist/Interfaces/InputInterfaces.d.ts +141 -0
  188. package/dist/Interfaces/InputInterfaces.js +1 -0
  189. package/dist/Interfaces/MessageInterfaces.d.ts +111 -0
  190. package/dist/Interfaces/MessageInterfaces.js +5 -0
  191. package/dist/Interfaces/TableInterfaces.d.ts +291 -0
  192. package/dist/Interfaces/TableInterfaces.js +1 -0
  193. package/dist/Interfaces/ThemeInterfaces.d.ts +17 -0
  194. package/dist/Interfaces/ThemeInterfaces.js +17 -0
  195. package/dist/Interfaces/TypeInterfaces.d.ts +4 -0
  196. package/dist/Interfaces/TypeInterfaces.js +1 -0
  197. package/dist/Server.Index.d.ts +2 -0
  198. package/dist/Server.Index.js +5 -0
  199. package/dist/Services/ApiProxy.d.ts +32 -0
  200. package/dist/Services/ApiProxy.js +111 -0
  201. package/dist/Services/BrowserApi.d.ts +78 -0
  202. package/dist/Services/BrowserApi.js +111 -0
  203. package/dist/Services/ServerApi.d.ts +49 -0
  204. package/dist/Services/ServerApi.js +75 -0
  205. package/dist/Services/ThemeService.d.ts +17 -0
  206. package/dist/Services/ThemeService.js +83 -0
  207. package/dist/Shared.Index.d.ts +43 -0
  208. package/dist/Shared.Index.js +47 -0
  209. package/package.json +82 -33
  210. package/src/Styles/Nexus.Base.css +70 -0
  211. package/src/Styles/Nexus.Button.css +151 -0
  212. package/src/Styles/Nexus.Calendar.css +275 -0
  213. package/src/Styles/Nexus.Choice.css +345 -0
  214. package/src/Styles/Nexus.Crud.css +84 -0
  215. package/src/Styles/Nexus.DateTime.css +81 -0
  216. package/src/Styles/Nexus.Dropdown.css +774 -0
  217. package/src/Styles/Nexus.Editor.css +297 -0
  218. package/src/Styles/Nexus.Form.css +298 -0
  219. package/src/Styles/Nexus.Index.css +34 -0
  220. package/src/Styles/Nexus.Input.css +637 -0
  221. package/src/Styles/Nexus.Markdown.css +265 -0
  222. package/src/Styles/Nexus.Menu.css +249 -0
  223. package/src/Styles/Nexus.Popup.css +731 -0
  224. package/src/Styles/Nexus.RichText.css +463 -0
  225. package/src/Styles/Nexus.Rows.css +566 -0
  226. package/src/Styles/Nexus.Slider.css +278 -0
  227. package/src/Styles/Nexus.Tab.Buttons.css +364 -0
  228. package/src/Styles/Nexus.Table.css +1014 -0
  229. package/src/Styles/Nexus.Theme.Picker.css +159 -0
  230. package/src/Styles/Nexus.Themes.css +194 -0
  231. package/src/Styles/Nexus.Time.css +147 -0
  232. package/src/Styles/Nexus.Toast.css +265 -0
  233. package/src/Styles/Nexus.Tokens.css +72 -0
  234. package/src/Styles/Nexus.Tree.css +435 -0
  235. package/src/api-services/authentication-service.tsx +0 -23
  236. package/src/api-services/preference-service.tsx +0 -5
  237. package/src/api-services/system-service.tsx +0 -34
  238. package/src/client.ts +0 -31
  239. package/src/components/documents/button.tsx +0 -142
  240. package/src/components/documents/icon-box.tsx +0 -93
  241. package/src/components/documents/page-title.tsx +0 -7
  242. package/src/components/documents/tab-button.tsx +0 -172
  243. package/src/components/documents/tag.tsx +0 -30
  244. package/src/components/index.js +0 -0
  245. package/src/components/inputs/checkbox-input.tsx +0 -66
  246. package/src/components/inputs/input-box.tsx +0 -48
  247. package/src/components/inputs/input-element.tsx +0 -65
  248. package/src/components/inputs/input-form.tsx +0 -164
  249. package/src/components/inputs/input.tsx +0 -181
  250. package/src/components/inputs/number-input.tsx +0 -108
  251. package/src/components/inputs/radiobox-input.tsx +0 -53
  252. package/src/components/inputs/textarea-input.tsx +0 -47
  253. package/src/components/inputs/textbox-input.tsx +0 -45
  254. package/src/components/layouts/global-dialogbox.tsx +0 -431
  255. package/src/components/layouts/global-layout.tsx +0 -59
  256. package/src/components/layouts/layout-helpers.tsx +0 -20
  257. package/src/components/layouts/panels/user-panel.tsx +0 -112
  258. package/src/components/layouts/utility-menu.tsx +0 -49
  259. package/src/components/panels/theme-panel.tsx +0 -46
  260. package/src/helpers/bitwise-helpers.tsx +0 -11
  261. package/src/helpers/browser-helpers.tsx +0 -156
  262. package/src/helpers/datasource-helpers.tsx +0 -99
  263. package/src/helpers/element-helpers.tsx +0 -57
  264. package/src/helpers/input-helpers.tsx +0 -74
  265. package/src/helpers/string-helpers.tsx +0 -28
  266. package/src/helpers/utility-helpers.tsx +0 -45
  267. package/src/helpers/validation-helpers.tsx +0 -302
  268. package/src/index.ts +0 -26
  269. package/src/interface.ts +0 -19
  270. package/src/interfaces/auth-token-interfaces.tsx +0 -6
  271. package/src/interfaces/browser-interfaces.tsx +0 -36
  272. package/src/interfaces/button-interfaces.tsx +0 -63
  273. package/src/interfaces/datasource-interfaces.tsx +0 -22
  274. package/src/interfaces/datatable-interfaces.tsx +0 -25
  275. package/src/interfaces/dialogbox-interfaces.tsx +0 -5
  276. package/src/interfaces/exception-interfaces.tsx +0 -99
  277. package/src/interfaces/http-interfaces.tsx +0 -129
  278. package/src/interfaces/icon-interfaces.tsx +0 -129
  279. package/src/interfaces/input-interfaces.tsx +0 -410
  280. package/src/interfaces/layout-interfaces.tsx +0 -191
  281. package/src/interfaces/menu-interfaces.tsx +0 -49
  282. package/src/interfaces/message-interfaces.tsx +0 -32
  283. package/src/interfaces/permission-interfaces.tsx +0 -9
  284. package/src/interfaces/storage-interfaces.tsx +0 -5
  285. package/src/interfaces/system-interfaces.tsx +0 -22
  286. package/src/interfaces/theme-interfaces.tsx +0 -123
  287. package/src/interfaces/type-interfaces.tsx +0 -28
  288. package/src/interfaces/user-interfaces.tsx +0 -47
  289. package/src/nexus-client.tsx +0 -21
  290. package/src/nexus.environments.tsx +0 -66
  291. package/src/proxy-api/proxy-backend.tsx +0 -60
  292. package/src/proxy-api/proxy-constants.tsx +0 -28
  293. package/src/proxy-api/proxy-helpers.tsx +0 -91
  294. package/src/proxy-api-client.tsx +0 -1
  295. package/src/proxy-api-server.tsx +0 -2
  296. package/src/services/http-client-services.tsx +0 -75
  297. package/src/services/http-services.tsx +0 -158
  298. package/src/services/loader-service.tsx +0 -185
  299. package/src/services/localstorage-service.tsx +0 -119
  300. package/src/services/message-services.tsx +0 -383
  301. package/src/services/theme-service.tsx +0 -161
  302. package/src/services/user-services.tsx +0 -10
  303. package/src/sso-config/auth-token-validation.ts +0 -16
  304. package/src/sso-config/callback-route.tsx +0 -35
  305. package/src/sso-config/cookie-encryption.ts +0 -51
  306. package/src/sso-config/cookie-helpers.tsx +0 -102
  307. package/src/sso-config/forgot-password-route.tsx +0 -36
  308. package/src/sso-config/oauth-callback-state.ts +0 -61
  309. package/src/sso-config/pkce-helpers.ts +0 -9
  310. package/src/sso-config/provider-complete-route.tsx +0 -18
  311. package/src/sso-config/redirect-context-actions.tsx +0 -45
  312. package/src/sso-config/redirect-context-helpers.tsx +0 -159
  313. package/src/sso-config/redirect-context-persist.tsx +0 -18
  314. package/src/sso-config/redirect-context-route.tsx +0 -45
  315. package/src/sso-config/refresh-route.tsx +0 -23
  316. package/src/sso-config/sign-in-route.tsx +0 -74
  317. package/src/sso-config/sign-out-route.tsx +0 -57
  318. package/src/sso-config/sign-up-route.tsx +0 -57
  319. package/src/sso-config/sso-backend-flow.ts +0 -38
  320. package/src/sso-config/sso-complete-route.tsx +0 -50
  321. package/src/sso-config/sso-config.ts +0 -59
  322. package/src/sso-config/sso-interfaces.tsx +0 -99
  323. package/src/sso-config/sso-response-helpers.tsx +0 -20
  324. package/src/sso-server.tsx +0 -21
  325. package/src/styles/nexus.animation.css +0 -269
  326. package/src/styles/nexus.core.css +0 -119
  327. package/src/styles/nexus.dialog.css +0 -144
  328. package/src/styles/nexus.icon.css +0 -51
  329. package/src/styles/nexus.input.css +0 -207
  330. package/src/styles/nexus.loader.css +0 -11
  331. package/src/styles/nexus.logic.css +0 -47
  332. package/src/styles/nexus.utility.css +0 -347
@@ -0,0 +1,291 @@
1
+ import type { CSSProperties, ReactNode, Ref } from "react";
2
+ import type { TableStore } from "../Helpers/TableStore.ts";
3
+ import type { Size, Tone } from "./TypeInterfaces.ts";
4
+ /** A row's id: its `rowKey` field, such as `id`. */
5
+ export type TableKey = string | number;
6
+ /** A row of a data table: any object. */
7
+ export type TableRow = object;
8
+ /** How a column shows its values. */
9
+ export type TableColumnFormat = "text" | "number" | "money" | "percent" | "date" | "time" | "date-time" | "boolean";
10
+ /** One of the values a column can hold, with its label: a status, a type. With a `tone`, the cell shows it as a tag. */
11
+ export interface TableColumnOption {
12
+ value: unknown;
13
+ label: string;
14
+ /** Draws the value as a tag with a dot of this color. */
15
+ tone?: Tone;
16
+ }
17
+ /** One column: which field it shows, how, and what the user can do with it. */
18
+ export interface TableColumn<TRow extends TableRow = TableRow> {
19
+ /** The field: `"name"`, or a path into the row, `"guest.name"`. It is also the column's id and its sort name. */
20
+ key: string;
21
+ /** The heading, and the column's name in the Columns menu and the details view. */
22
+ label: string;
23
+ /** Default `text`. Numbers, money, and percents line up at the end; dates and times follow the user's settings. */
24
+ format?: TableColumnFormat;
25
+ /** Digits after the decimal point of a number (money: 2). */
26
+ decimals?: number;
27
+ /** Text before a number, such as "Rs. ". */
28
+ prefix?: string;
29
+ /** Text after a number, such as " kg". */
30
+ suffix?: string;
31
+ /** Labels for the values the column holds, such as the names of an enum's numbers. */
32
+ options?: readonly TableColumnOption[];
33
+ /** The value when it is not one field: `row => row.first + " " + row.last`. Sorting and searching use it too. */
34
+ value?: (row: TRow) => unknown;
35
+ /** Draws the cell. Default: the value in the column's format. */
36
+ render?: (row: TRow, value: unknown) => ReactNode;
37
+ /** Text the search looks in. Default: the value as text (labels of `options`, ISO dates). */
38
+ text?: (row: TRow) => string;
39
+ /** Width: pixels or a CSS length ("12rem"). Default: by content. */
40
+ width?: number | string;
41
+ /** Narrowest the column gets. Default by format. */
42
+ minWidth?: number | string;
43
+ /** Default: `end` for numbers, money, and percents, `center` for booleans, else `start`. */
44
+ align?: "start" | "center" | "end";
45
+ /** Default true. */
46
+ sortable?: boolean;
47
+ /** Name the server sorts by, when it differs from `key`. */
48
+ sortKey?: string;
49
+ /** The table's search looks in this column. Default true. (A server searches as it likes.) */
50
+ searchable?: boolean;
51
+ /** Starts hidden; the Columns menu shows it. */
52
+ hidden?: boolean;
53
+ /** The Columns menu can hide it. Default true. */
54
+ hideable?: boolean;
55
+ /** Long text wraps onto more lines instead of ending in "…". */
56
+ wrap?: boolean;
57
+ /** The user can drag the heading to another place, or move it from its menu. Default true. */
58
+ movable?: boolean;
59
+ /** The user can drag the edge of the heading to change the width. Default true; `false` for a column that must keep its width. */
60
+ resizable?: boolean;
61
+ /** The user can keep the column on the left or the right while the others scroll. Default true. */
62
+ pinnable?: boolean;
63
+ /** Pinned before the user pins anything: `left` keeps it at the start, `right` at the end. */
64
+ pinned?: TablePinSide;
65
+ }
66
+ /** Which side a pinned column stays on while the others scroll. */
67
+ export type TablePinSide = "left" | "right";
68
+ export type TableSortDirection = "asc" | "desc";
69
+ export interface TableSort {
70
+ /** A column's `key` (its `sortKey` goes to a server). */
71
+ key: string;
72
+ direction: TableSortDirection;
73
+ }
74
+ /** What the table shows: the search, the sort, and the page. */
75
+ export interface TableQuery {
76
+ /** The search text, trimmed. */
77
+ search: string;
78
+ sort: TableSort | null;
79
+ /** The page, from 1. */
80
+ page: number;
81
+ pageSize: number;
82
+ }
83
+ /** One page of rows, as a server sends it. */
84
+ export interface TablePage<TRow extends TableRow = TableRow> {
85
+ rows: readonly TRow[];
86
+ /** Every row there is. Default: the rows given. */
87
+ total?: number;
88
+ /** The rows that match the search. Default: `total`. */
89
+ matches?: number;
90
+ }
91
+ /**
92
+ * Loads rows for a query: every row (a list the table searches, sorts, and pages itself) or one page (the server did it).
93
+ * It may answer at once, without a promise, such as from a cache.
94
+ */
95
+ export type TableLoader<TRow extends TableRow = TableRow> = (query: TableQuery, signal: AbortSignal) => TablePage<TRow> | readonly TRow[] | Promise<TablePage<TRow> | readonly TRow[]>;
96
+ /** `client`: the table has every row and pages them itself. `server`: each page comes from the loader. */
97
+ export type TablePaging = "client" | "server";
98
+ /** `loading`: the first rows are on their way. `ready`: rows (or none) are shown. `error`: the rows could not load. */
99
+ export type TableStatus = "loading" | "ready" | "error";
100
+ /** What the table shows now. A new object after every change. */
101
+ export interface TableState<TRow extends TableRow = TableRow> {
102
+ status: TableStatus;
103
+ /** A load runs while rows show: another page, a search, a sort, a reload. */
104
+ refreshing: boolean;
105
+ /** Why the rows could not load. */
106
+ error: string | null;
107
+ /** The rows on the page. */
108
+ rows: readonly TRow[];
109
+ /** How many rows come before the page: its first row is number `offset + 1`. */
110
+ offset: number;
111
+ /** Every row there is. */
112
+ total: number;
113
+ /** The rows that match the search. */
114
+ matches: number;
115
+ query: TableQuery;
116
+ /** The selected rows by key (keys as text), in the order they were picked. */
117
+ selected: ReadonlyMap<string, TRow>;
118
+ /** Rows with an action running. */
119
+ busy: ReadonlySet<string>;
120
+ /** Rows just added or changed, highlighted for a moment. */
121
+ flashed: ReadonlySet<string>;
122
+ /** Keys of the hidden columns. */
123
+ hidden: ReadonlySet<string>;
124
+ /** Column keys in the order the user put them. Empty: the order the columns were given in. */
125
+ order: readonly string[];
126
+ /** Widths the user set, in pixels, by column key (and by `#index`, `#actions` for the table's own columns). */
127
+ widths: Readonly<Record<string, number>>;
128
+ /** The side each pinned column stays on, by column key. */
129
+ pinned: Readonly<Record<string, TablePinSide>>;
130
+ }
131
+ /** A column as the table draws it: where it sits, whether it is pinned, and how far from that edge. */
132
+ export interface TableViewColumn<TRow extends TableRow = TableRow> {
133
+ column: TableColumn<TRow>;
134
+ /** The side it stays on, or null when it scrolls with the rest. */
135
+ pin: TablePinSide | null;
136
+ /** Pixels from that edge, once the table has measured the columns before it. */
137
+ offset: number;
138
+ /** The last pinned column of its side: the one that shows the shadow while columns scroll under it. */
139
+ edge: boolean;
140
+ /** The user can drag its edge to change the width. */
141
+ resizable: boolean;
142
+ /** The user can drag it to another place. */
143
+ movable: boolean;
144
+ /** Its width in pixels, once the user has set one. */
145
+ width?: number;
146
+ }
147
+ /** An item of the table's options menu (⋮): Import, Print, a report of the page's own. */
148
+ export interface TableMenuAction {
149
+ /** Tells items apart; a test or a style can find it by `data-action`. */
150
+ id: string;
151
+ label: string;
152
+ icon?: ReactNode;
153
+ /** A second line in the menu. */
154
+ description?: string;
155
+ /** `danger` for items that lose something. */
156
+ tone?: "danger";
157
+ disabled?: boolean;
158
+ /** A line above the item, to start a group. */
159
+ separator?: boolean;
160
+ onSelect: () => void;
161
+ }
162
+ /** An action on one row, in its row: an icon button (`inline`) or an item of the row's menu. */
163
+ export interface TableRowAction<TRow extends TableRow = TableRow> {
164
+ /** Tells actions apart; a test or a style can find it by `data-action`. */
165
+ id: string;
166
+ label: string;
167
+ /** Needed for an `inline` action, which shows only its icon. */
168
+ icon?: ReactNode;
169
+ /** A second line in the menu. */
170
+ description?: string;
171
+ /** `danger` for actions that lose something. */
172
+ tone?: "danger";
173
+ /** Shown as an icon button on the row; the rest are in the row's menu. */
174
+ inline?: boolean;
175
+ disabled?: boolean;
176
+ /** Runs the action. While a promise it returns runs, the row is busy and its actions wait. */
177
+ onSelect: (row: TRow) => unknown;
178
+ }
179
+ /** An action on the selected rows, on the bar that shows while rows are selected. */
180
+ export interface TableMassAction<TRow extends TableRow = TableRow> {
181
+ id: string;
182
+ label: string;
183
+ icon?: ReactNode;
184
+ tone?: "danger";
185
+ disabled?: boolean;
186
+ /** Runs the action. While a promise it returns runs, the bar waits. */
187
+ onSelect: (rows: TRow[]) => unknown;
188
+ }
189
+ /** Props of `DataTable`. */
190
+ export interface DataTableProps<TRow extends TableRow = TableRow> {
191
+ /** The columns, in their order on screen. Keep the array stable (a constant or `useMemo`). */
192
+ columns: readonly TableColumn<TRow>[];
193
+ /** Every row, given by the page. The table searches, sorts, and pages them. */
194
+ rows?: readonly TRow[];
195
+ /** Loads the rows: every row once (`paging="client"`), or one page per query (`paging="server"`). */
196
+ load?: TableLoader<TRow>;
197
+ /** Default `client`. */
198
+ paging?: TablePaging;
199
+ /** Loads again, from the first page, when it changes: another list behind the same table, such as a CRUD's archive. */
200
+ loadKey?: string | number;
201
+ /** The field that tells rows apart. Default `id`. */
202
+ rowKey?: string | ((row: TRow) => TableKey);
203
+ /** Names a row for screen readers and messages ("Select Sita Sharma"). Default: the first column's text. */
204
+ rowLabel?: (row: TRow) => string;
205
+ /** The store behind the table, from `useTable()`, to reload, change rows, or read the selection from outside. */
206
+ table?: TableStore<TRow>;
207
+ /** The table's name for screen readers, such as "Guests". A visible heading can name it through `aria-labelledby`. */
208
+ "aria-label"?: string;
209
+ "aria-labelledby"?: string;
210
+ /** A search box. Default true. */
211
+ searchable?: boolean;
212
+ /** Default "Search…". */
213
+ searchPlaceholder?: string;
214
+ /** Before the search box, on the left of the bar: tabs, filters. */
215
+ toolbar?: ReactNode;
216
+ /** At the end of the bar: an Add button. */
217
+ actions?: ReactNode;
218
+ /** The Columns menu, to show and hide columns. Default true. */
219
+ columnsMenu?: boolean;
220
+ /** A Reload button. Default true when rows are loaded. */
221
+ reloadable?: boolean;
222
+ /** When the user presses Reload, before the rows load again: drop a cache of your own. */
223
+ onReload?: () => void;
224
+ /** Columns can be dragged into another order (also from each heading's menu). Default true. */
225
+ reorderable?: boolean;
226
+ /** Columns can be resized by dragging the edge of a heading. Default true; a single column opts out with `resizable: false`. */
227
+ resizable?: boolean;
228
+ /** Columns can be pinned to the left or the right. Default true; a single column opts out with `pinnable: false`. */
229
+ pinnable?: boolean;
230
+ /** Items of the options menu (⋮), after Export and Print: Import, a report, anything of the page's own. */
231
+ moreActions?: readonly TableMenuAction[];
232
+ /** An Export item in the options menu, which writes the shown columns as a CSV file. Default true. */
233
+ exportable?: boolean;
234
+ /** A Print item in the options menu, which prints the shown columns. Default true. */
235
+ printable?: boolean;
236
+ /** Name of the file an export writes, and the heading a print shows. Default: the table's `aria-label`, else "Table". */
237
+ exportName?: string;
238
+ /** An Import item in the options menu, which calls this: the page asks for a file and loads it. */
239
+ onImport?: () => void;
240
+ /** A checkbox on each row, and a bar of `massActions` while rows are selected. */
241
+ selectable?: boolean;
242
+ /** Most rows that can be selected. Default 500. */
243
+ maxSelection?: number;
244
+ /** After the selection changes. */
245
+ onSelectionChange?: (rows: TRow[]) => void;
246
+ /** Actions on the selected rows. A function gets the selected rows. */
247
+ massActions?: readonly TableMassAction<TRow>[] | ((rows: TRow[]) => readonly TableMassAction<TRow>[]);
248
+ /** Actions of each row. */
249
+ rowActions?: (row: TRow) => readonly TableRowAction<TRow>[];
250
+ /** A double-click on a row, such as to open its details. */
251
+ onRowOpen?: (row: TRow) => void;
252
+ /**
253
+ * Rows kept in a section above the page, which the user folds open: the records they pinned. They are the rows as
254
+ * they came from their own endpoint, and the same records also show in the list below. Leave it out for no section.
255
+ */
256
+ pinnedRows?: readonly TRow[];
257
+ /** The pinned rows are on their way: the section shows that it is loading. */
258
+ pinnedLoading?: boolean;
259
+ /** What the section is called. Default "Pinned". */
260
+ pinnedLabel?: string;
261
+ /** Most rows that can be pinned, shown beside the count so the user knows the limit. */
262
+ pinnedMax?: number;
263
+ /** Rows per page. Default 10, or the user's last choice with `stateKey`. */
264
+ pageSize?: number;
265
+ /** Choices of rows per page. Default 10, 25, 50, 100. */
266
+ pageSizes?: readonly number[];
267
+ /** The sort before the user picks one. Default none: the order the rows came in. */
268
+ defaultSort?: TableSort | null;
269
+ /**
270
+ * Row numbers in the first column. Default: on when `selectable`, where the number becomes the row's checkbox as soon
271
+ * as the pointer is over the row or anything is selected.
272
+ */
273
+ numbered?: boolean;
274
+ /** Remembers the page size, the sort, hidden columns, the order, widths, and pins of the columns, and whether the
275
+ * pinned section is open, on this device. */
276
+ stateKey?: string;
277
+ /** Milliseconds after the last key before a search goes to a server. Default 300; a table with every row searches at once. */
278
+ searchDelay?: number;
279
+ /** Shown when there are no rows at all. Default "No records yet." */
280
+ emptyMessage?: ReactNode;
281
+ /** Beside the empty message, such as an Add button. */
282
+ emptyAction?: ReactNode;
283
+ /** The tallest the table grows before its rows scroll under a header that stays: pixels or a CSS length. */
284
+ maxHeight?: number | string;
285
+ /** Row height and text size. Default `md`. */
286
+ size?: Extract<Size, "sm" | "md">;
287
+ id?: string;
288
+ className?: string;
289
+ style?: CSSProperties;
290
+ ref?: Ref<TableStore<TRow>>;
291
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ /** Light, dark, or whatever the operating system uses. */
2
+ export type ThemeMode = "light" | "dark" | "system";
3
+ export interface ThemeOption {
4
+ /** The `data-nx-theme` value: lowercase letters, digits, and dashes. */
5
+ id: string;
6
+ name: string;
7
+ description: string;
8
+ }
9
+ /** The themes in `nexus-shared/styles.css`. Each has a light and a dark palette. */
10
+ export declare const NEXUS_THEMES: readonly ThemeOption[];
11
+ export declare const DEFAULT_THEME = "nexus";
12
+ /** Browser storage keys for the saved choice. */
13
+ export declare const THEME_STORAGE_KEY = "nx-theme";
14
+ export declare const THEME_MODE_STORAGE_KEY = "nx-mode";
15
+ /** Attributes on `<html>` that select the theme and the mode. Without `data-nx-mode`, the system setting applies. */
16
+ export declare const THEME_ATTRIBUTE = "data-nx-theme";
17
+ export declare const THEME_MODE_ATTRIBUTE = "data-nx-mode";
@@ -0,0 +1,17 @@
1
+ /** The themes in `nexus-shared/styles.css`. Each has a light and a dark palette. */
2
+ export const NEXUS_THEMES = [
3
+ { id: "nexus", name: "Nexus", description: "Neutral grays with a confident blue" },
4
+ { id: "github", name: "GitHub", description: "Primer grays with GitHub green" },
5
+ { id: "nord", name: "Nord", description: "Arctic, north-bluish calm" },
6
+ { id: "dracula", name: "Dracula", description: "The dark purple classic, Alucard in light" },
7
+ { id: "solarized", name: "Solarized", description: "Warm cream or deep teal, precise accents" },
8
+ { id: "catppuccin", name: "Catppuccin", description: "Soothing pastels: Latte and Mocha" },
9
+ { id: "rose-pine", name: "Rosé Pine", description: "Muted pine, iris, and rose" },
10
+ ];
11
+ export const DEFAULT_THEME = "nexus";
12
+ /** Browser storage keys for the saved choice. */
13
+ export const THEME_STORAGE_KEY = "nx-theme";
14
+ export const THEME_MODE_STORAGE_KEY = "nx-mode";
15
+ /** Attributes on `<html>` that select the theme and the mode. Without `data-nx-mode`, the system setting applies. */
16
+ export const THEME_ATTRIBUTE = "data-nx-theme";
17
+ export const THEME_MODE_ATTRIBUTE = "data-nx-mode";
@@ -0,0 +1,4 @@
1
+ /** A value that may be missing: `string | UN`. */
2
+ export type UN = undefined | null;
3
+ export type Size = "sm" | "md" | "lg";
4
+ export type Tone = "neutral" | "primary" | "success" | "warning" | "danger" | "info";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./Services/ApiProxy.ts";
2
+ export * from "./Services/ServerApi.ts";
@@ -0,0 +1,5 @@
1
+ // Server-only code: layouts that read configuration, API helpers that use secrets.
2
+ // Import from "nexus-shared/server".
3
+ // Services
4
+ export * from "./Services/ApiProxy.js";
5
+ export * from "./Services/ServerApi.js";
@@ -0,0 +1,32 @@
1
+ import type { ApiModuleValue } from "../Interfaces/ApiInterfaces.ts";
2
+ export interface ApiProxyOptions {
3
+ /** The user's token for the backend, such as from the session cookie. Without one, the request's own Authorization header goes on. */
4
+ token?: (request: Request) => string | null | undefined | Promise<string | null | undefined>;
5
+ /** Headers to add, such as a tenant from the session. */
6
+ headers?: (request: Request) => Record<string, string> | undefined | Promise<Record<string, string> | undefined>;
7
+ /** Serves only these modules, of those the app's `ApiModules` sends through the proxy. Default: all of those. */
8
+ allow?: readonly ApiModuleValue[];
9
+ /** Milliseconds to wait for the backend to start answering. Default 60,000. */
10
+ timeout?: number;
11
+ /** The `fetch` to use. Default: the global one. */
12
+ fetch?: typeof fetch;
13
+ }
14
+ /** What a Next.js route handler for `[module]/[...path]` receives. */
15
+ export interface ApiProxyContext {
16
+ params: Promise<{
17
+ module: string;
18
+ path?: string[];
19
+ }>;
20
+ }
21
+ /**
22
+ * Makes the route handlers of the proxy. Only the modules' configured roots can be reached: a path cannot climb out of
23
+ * its module (`..` is refused), and the query goes on unchanged.
24
+ */
25
+ export declare function createApiProxy(options?: ApiProxyOptions): {
26
+ GET: (request: Request, context: ApiProxyContext) => Promise<Response>;
27
+ HEAD: (request: Request, context: ApiProxyContext) => Promise<Response>;
28
+ POST: (request: Request, context: ApiProxyContext) => Promise<Response>;
29
+ PUT: (request: Request, context: ApiProxyContext) => Promise<Response>;
30
+ PATCH: (request: Request, context: ApiProxyContext) => Promise<Response>;
31
+ DELETE: (request: Request, context: ApiProxyContext) => Promise<Response>;
32
+ };
@@ -0,0 +1,111 @@
1
+ import { DEFAULT_API_TIMEOUT, isFrameworkError } from "../Helpers/ApiClient.js";
2
+ import { getApiModules } from "../Helpers/ApiModules.js";
3
+ import { joinUrl } from "../Helpers/ApiRoutes.js";
4
+ import { buildMessage } from "../Helpers/MessageBuilder.js";
5
+ import { serverModuleRoot } from "./ServerApi.js";
6
+ const METHODS = new Set(["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"]);
7
+ /** Request headers that belong to this hop, or to the app (its cookies), not to the backend. */
8
+ const REQUEST_HEADERS_TO_SKIP = new Set(["host", "connection", "content-length", "transfer-encoding", "keep-alive", "upgrade", "cookie", "te", "trailer", "proxy-authorization", "proxy-connection", "accept-encoding"]);
9
+ /**
10
+ * Response headers that belong to the backend's hop. `content-encoding` and `content-length` go too: `fetch` has already
11
+ * decompressed the body, so passing them on would make the browser decode it twice.
12
+ */
13
+ const RESPONSE_HEADERS_TO_SKIP = new Set(["connection", "transfer-encoding", "keep-alive", "proxy-authenticate", "proxy-authorization", "te", "trailer", "upgrade", "content-encoding", "content-length"]);
14
+ /** An answer the client reads like the backend's own. */
15
+ function failure(status, message, messageCode) {
16
+ return Response.json({ isSuccess: false, code: status, message, messageCode }, { status });
17
+ }
18
+ /** A backend redirect to its own host, pointed back through the proxy. */
19
+ function rewriteLocation(location, root, module, proxyPath) {
20
+ const target = new URL(location, root);
21
+ if (target.host !== root.host)
22
+ return location;
23
+ const base = root.pathname.replace(/\/+$/, "");
24
+ const relative = target.pathname.startsWith(`${base}/`) ? target.pathname.slice(base.length + 1) : target.pathname.replace(/^\/+/, "");
25
+ return `${joinUrl(joinUrl(proxyPath, module), relative)}${target.search}`;
26
+ }
27
+ /**
28
+ * Makes the route handlers of the proxy. Only the modules' configured roots can be reached: a path cannot climb out of
29
+ * its module (`..` is refused), and the query goes on unchanged.
30
+ */
31
+ export function createApiProxy(options = {}) {
32
+ async function handle(request, context) {
33
+ const method = request.method.toUpperCase();
34
+ if (!METHODS.has(method))
35
+ return failure(405, buildMessage("reason", { status: 405 }), "METHOD_NOT_ALLOWED");
36
+ const { module: key, path = [] } = await context.params;
37
+ // Asked on every request, so the app's modules count even when they were registered after this route was made.
38
+ const modules = getApiModules();
39
+ const info = modules.info(key);
40
+ if (!info || (options.allow && !options.allow.includes(info.module)))
41
+ return failure(404, `No API module is named "${key}".`, "MODULE_NOT_FOUND");
42
+ if (!modules.proxies(info.module))
43
+ return failure(404, `The ${info.label} API is not called through this app's proxy.`, "MODULE_NOT_PROXIED");
44
+ if (path.some(segment => segment === "." || segment === ".." || /[\\/]/.test(segment)))
45
+ return failure(400, "The API path is not valid.", "INVALID_PATH");
46
+ const incoming = new URL(request.url);
47
+ let root;
48
+ try {
49
+ root = new URL(await serverModuleRoot(info.module, incoming.origin));
50
+ }
51
+ catch (error) {
52
+ if (isFrameworkError(error))
53
+ throw error;
54
+ return failure(500, error instanceof Error ? error.message : String(error), "MODULE_NOT_CONFIGURED");
55
+ }
56
+ const target = new URL(joinUrl(root.toString(), path.map(encodeURIComponent).join("/")));
57
+ target.search = incoming.search;
58
+ const headers = new Headers();
59
+ request.headers.forEach((value, name) => {
60
+ if (!REQUEST_HEADERS_TO_SKIP.has(name.toLowerCase()))
61
+ headers.set(name, value);
62
+ });
63
+ for (const [name, value] of Object.entries((await options.headers?.(request)) ?? {}))
64
+ headers.set(name, value);
65
+ const token = await options.token?.(request);
66
+ if (token)
67
+ headers.set("Authorization", /^bearer /i.test(token) ? token : `Bearer ${token}`);
68
+ const controller = new AbortController();
69
+ const timeout = options.timeout ?? DEFAULT_API_TIMEOUT;
70
+ let timedOut = false;
71
+ const timer = setTimeout(() => {
72
+ timedOut = true;
73
+ controller.abort();
74
+ }, timeout);
75
+ // The browser left: stop waiting for the backend.
76
+ const leave = () => controller.abort();
77
+ request.signal?.addEventListener("abort", leave, { once: true });
78
+ let answer;
79
+ try {
80
+ answer = await (options.fetch ?? globalThis.fetch)(target, {
81
+ method,
82
+ headers,
83
+ body: method === "GET" || method === "HEAD" ? undefined : await request.arrayBuffer(),
84
+ redirect: "manual",
85
+ cache: "no-store",
86
+ signal: controller.signal,
87
+ });
88
+ }
89
+ catch (error) {
90
+ if (isFrameworkError(error))
91
+ throw error;
92
+ if (timedOut)
93
+ return failure(504, buildMessage("reason", { timeout: true }), "BACKEND_TIMEOUT");
94
+ return failure(502, `The ${info.label} API cannot be reached. Try again in a moment.`, "BACKEND_UNREACHABLE");
95
+ }
96
+ finally {
97
+ // The timeout covers the wait for the answer to start; a long download then streams through.
98
+ clearTimeout(timer);
99
+ request.signal?.removeEventListener("abort", leave);
100
+ }
101
+ const responseHeaders = new Headers();
102
+ answer.headers.forEach((value, name) => {
103
+ const lower = name.toLowerCase();
104
+ if (RESPONSE_HEADERS_TO_SKIP.has(lower))
105
+ return;
106
+ responseHeaders.append(name, lower === "location" ? rewriteLocation(value, root, info.key, modules.proxyPath) : value);
107
+ });
108
+ return new Response(method === "HEAD" ? null : answer.body, { status: answer.status, statusText: answer.statusText, headers: responseHeaders });
109
+ }
110
+ return { GET: handle, HEAD: handle, POST: handle, PUT: handle, PATCH: handle, DELETE: handle };
111
+ }
@@ -0,0 +1,78 @@
1
+ import { type ConfirmOptions } from "../Components/Layouts/MessageBox.tsx";
2
+ import { type ApiCall } from "../Helpers/ApiClient.ts";
3
+ import { type ApiToastDefaults, type ApiToastOption } from "../Helpers/ApiToasts.ts";
4
+ import type { ApiCallOptions, ApiResult, ApiTarget } from "../Interfaces/ApiInterfaces.ts";
5
+ import type { DropdownItem, DropdownPage, DropdownPageRequest } from "../Interfaces/InputInterfaces.ts";
6
+ /** Options of a browser call, on top of every call's options. */
7
+ export interface BrowserApiOptions {
8
+ /** Toasts for this call. Default: errors always, successes for POST, PUT, PATCH, and DELETE. See `ApiToastOption`. */
9
+ toast?: ApiToastOption;
10
+ }
11
+ /** How browser calls behave. Where they go (the proxy or each module's root) is the app's `ApiModules`. */
12
+ export interface BrowserApiConfig {
13
+ /** Headers on every call, such as the tenant or branch. */
14
+ headers?: (call: ApiCall<BrowserApiOptions>) => Record<string, string> | undefined;
15
+ /** A bearer token for every call. Leave it out with the proxy, which adds the token from the user's cookie. */
16
+ token?: (call: ApiCall<BrowserApiOptions>) => string | null | undefined;
17
+ /** Cookies on calls straight to a module on another origin: `include`. Default: the browser's (same origin only). */
18
+ credentials?: RequestCredentials;
19
+ /** Milliseconds to wait for an answer. Default 60,000. */
20
+ timeout?: number;
21
+ /** Which toasts show when a call does not say. Default: errors always, successes for changes. */
22
+ toast?: ApiToastDefaults;
23
+ /** After a 401, or an expired token (Nexus error 2003), such as to send the user to sign in. The error toast shows too. */
24
+ onSignedOut?: (result: ApiResult) => void;
25
+ /** After every answer, such as to log failures. */
26
+ onResult?: (result: ApiResult, call: ApiCall<BrowserApiOptions>) => void;
27
+ }
28
+ /**
29
+ * Sets up `api` for the app. Call it once in a client module that the root layout loads; later calls change only the
30
+ * settings they name. Nothing is needed when the proxy is at `/api/app` and the defaults suit.
31
+ */
32
+ export declare function configureApi(config: BrowserApiConfig): void;
33
+ /** Options of `api.confirm`: the call's, and changes to the question. */
34
+ export type ConfirmApiOptions = ApiCallOptions & BrowserApiOptions & {
35
+ question?: Partial<ConfirmOptions>;
36
+ };
37
+ /**
38
+ * Asks first, then sends. The question comes from the message builder ("Delete Room 204?", "This cannot be undone.",
39
+ * a Delete button, in red for actions that lose something). Resolves with the answer, or `null` when the user said no.
40
+ */
41
+ declare function confirmThenSend<T = unknown>(target: ApiTarget, { question, ...options }?: ConfirmApiOptions): Promise<ApiResult<T> | null>;
42
+ /**
43
+ * Calls APIs from the browser, with toasts.
44
+ *
45
+ * @example
46
+ * const ROOMS = MODULES.controller(NexusModule.Reservation, "Room", "room"); // MODULES: the app's defineApiModules(…)
47
+ *
48
+ * const rooms = await api.get<Room[]>(ROOMS.listing); // error toast if it fails
49
+ * if (rooms.ok) setRows(rooms.result);
50
+ *
51
+ * await api.put(ROOMS.update, values, { subject: `Room ${values.number}` }); // "Room 204 saved." or why not
52
+ * await api.delete(ROOMS.delete, { params: { id }, toast: { loading: true } });
53
+ * await api.confirm(ROOMS.delete, { params: { id }, subject: "Room 204" }); // "Delete Room 204?" first; null if not
54
+ * await api.post("/api/demo-rooms", values, { toast: false }); // a URL, no toasts
55
+ */
56
+ export declare const api: import("../Shared.Index.ts").ApiClient<BrowserApiOptions> & {
57
+ confirm: typeof confirmThenSend;
58
+ };
59
+ export interface ApiOptionsLoaderOptions<TRow, TItem> {
60
+ /** Turns a row the API sends into a dropdown item. Default: the row is the item. */
61
+ toItem?: (row: TRow) => TItem;
62
+ /**
63
+ * What is sent for a page. Default, as Nexus pagination APIs take it: `{ searchKeyword, skipCount, maxCount }`, in the
64
+ * body for POST and in the query for GET.
65
+ */
66
+ request?: (page: DropdownPageRequest) => Record<string, unknown>;
67
+ /** Other options of the call, such as `params` or `headers`. */
68
+ call?: Omit<ApiCallOptions, "body" | "signal">;
69
+ }
70
+ /**
71
+ * A dropdown's `loadOptions` for an API that sends pages (`{ results, totalCount, filterCount }`) or a whole list.
72
+ * Failures show in the dropdown, with Retry, not as a toast.
73
+ *
74
+ * @example
75
+ * <Dropdown name="roomId" label="Room" valueKey="id" labelKey="number" loadOptions={apiOptionsLoader(ROOMS.pagination)} />
76
+ */
77
+ export declare function apiOptionsLoader<TRow extends DropdownItem = DropdownItem, TItem extends DropdownItem = TRow>(target: ApiTarget, { toItem, request, call }?: ApiOptionsLoaderOptions<TRow, TItem>): (page: DropdownPageRequest) => Promise<DropdownPage<TItem>>;
78
+ export {};