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.
- package/CHANGELOG.md +262 -0
- package/LICENSE +21 -0
- package/README.md +1000 -0
- package/dist/Client.Index.d.ts +55 -0
- package/dist/Client.Index.js +60 -0
- package/dist/Components/Chats/Chat.d.ts +28 -0
- package/dist/Components/Chats/Chat.js +19 -0
- package/dist/Components/Chats/ChatButton.d.ts +26 -0
- package/dist/Components/Chats/ChatButton.js +41 -0
- package/dist/Components/Chats/ChatComposer.d.ts +41 -0
- package/dist/Components/Chats/ChatComposer.js +177 -0
- package/dist/Components/Chats/ChatConversations.d.ts +35 -0
- package/dist/Components/Chats/ChatConversations.js +38 -0
- package/dist/Components/Chats/ChatPanel.d.ts +66 -0
- package/dist/Components/Chats/ChatPanel.js +94 -0
- package/dist/Components/Chats/ChatParts.d.ts +87 -0
- package/dist/Components/Chats/ChatParts.js +100 -0
- package/dist/Components/Chats/ChatThread.d.ts +22 -0
- package/dist/Components/Chats/ChatThread.js +96 -0
- package/dist/Components/Documents/Button.d.ts +29 -0
- package/dist/Components/Documents/Button.js +11 -0
- package/dist/Components/Documents/Menu.d.ts +102 -0
- package/dist/Components/Documents/Menu.js +242 -0
- package/dist/Components/Documents/SplitButton.d.ts +64 -0
- package/dist/Components/Documents/SplitButton.js +129 -0
- package/dist/Components/Documents/TabButtons.d.ts +80 -0
- package/dist/Components/Documents/TabButtons.js +38 -0
- package/dist/Components/Forms/ApiForm.d.ts +23 -0
- package/dist/Components/Forms/ApiForm.js +100 -0
- package/dist/Components/Forms/Crud.d.ts +17 -0
- package/dist/Components/Forms/Crud.js +708 -0
- package/dist/Components/Forms/CrudParts.d.ts +15 -0
- package/dist/Components/Forms/CrudParts.js +36 -0
- package/dist/Components/Forms/ExcelImport.d.ts +42 -0
- package/dist/Components/Forms/ExcelImport.js +190 -0
- package/dist/Components/Forms/Form.d.ts +52 -0
- package/dist/Components/Forms/Form.js +323 -0
- package/dist/Components/Forms/SubmitForm.d.ts +65 -0
- package/dist/Components/Forms/SubmitForm.js +198 -0
- package/dist/Components/Inputs/Calendar.d.ts +69 -0
- package/dist/Components/Inputs/Calendar.js +258 -0
- package/dist/Components/Inputs/CheckBox.d.ts +53 -0
- package/dist/Components/Inputs/CheckBox.js +87 -0
- package/dist/Components/Inputs/CheckBoxGroup.d.ts +20 -0
- package/dist/Components/Inputs/CheckBoxGroup.js +80 -0
- package/dist/Components/Inputs/ChoiceField.d.ts +122 -0
- package/dist/Components/Inputs/ChoiceField.js +169 -0
- package/dist/Components/Inputs/DatePicker.d.ts +54 -0
- package/dist/Components/Inputs/DatePicker.js +246 -0
- package/dist/Components/Inputs/DateRangePicker.d.ts +62 -0
- package/dist/Components/Inputs/DateRangePicker.js +283 -0
- package/dist/Components/Inputs/DateTimePicker.d.ts +75 -0
- package/dist/Components/Inputs/DateTimePicker.js +400 -0
- package/dist/Components/Inputs/Dropdown.d.ts +117 -0
- package/dist/Components/Inputs/Dropdown.js +839 -0
- package/dist/Components/Inputs/DropdownParts.d.ts +84 -0
- package/dist/Components/Inputs/DropdownParts.js +102 -0
- package/dist/Components/Inputs/EditorShell.d.ts +45 -0
- package/dist/Components/Inputs/EditorShell.js +214 -0
- package/dist/Components/Inputs/Field.d.ts +53 -0
- package/dist/Components/Inputs/Field.js +16 -0
- package/dist/Components/Inputs/GroupForm.d.ts +20 -0
- package/dist/Components/Inputs/GroupForm.js +172 -0
- package/dist/Components/Inputs/InputField.d.ts +59 -0
- package/dist/Components/Inputs/InputField.js +169 -0
- package/dist/Components/Inputs/InputRenderer.d.ts +37 -0
- package/dist/Components/Inputs/InputRenderer.js +99 -0
- package/dist/Components/Inputs/MarkdownEditor.d.ts +67 -0
- package/dist/Components/Inputs/MarkdownEditor.js +289 -0
- package/dist/Components/Inputs/NumberBox.d.ts +53 -0
- package/dist/Components/Inputs/NumberBox.js +228 -0
- package/dist/Components/Inputs/RadioGroup.d.ts +20 -0
- package/dist/Components/Inputs/RadioGroup.js +43 -0
- package/dist/Components/Inputs/ReadOnlyNotice.d.ts +36 -0
- package/dist/Components/Inputs/ReadOnlyNotice.js +117 -0
- package/dist/Components/Inputs/RichTextEditor.d.ts +103 -0
- package/dist/Components/Inputs/RichTextEditor.js +1170 -0
- package/dist/Components/Inputs/RichTextParts.d.ts +63 -0
- package/dist/Components/Inputs/RichTextParts.js +157 -0
- package/dist/Components/Inputs/RowsInput.d.ts +115 -0
- package/dist/Components/Inputs/RowsInput.js +308 -0
- package/dist/Components/Inputs/Slider.d.ts +87 -0
- package/dist/Components/Inputs/Slider.js +216 -0
- package/dist/Components/Inputs/TabularForm.d.ts +27 -0
- package/dist/Components/Inputs/TabularForm.js +348 -0
- package/dist/Components/Inputs/TextArea.d.ts +43 -0
- package/dist/Components/Inputs/TextArea.js +31 -0
- package/dist/Components/Inputs/TextBox.d.ts +52 -0
- package/dist/Components/Inputs/TextBox.js +58 -0
- package/dist/Components/Inputs/TextField.d.ts +31 -0
- package/dist/Components/Inputs/TextField.js +35 -0
- package/dist/Components/Inputs/TimePanel.d.ts +34 -0
- package/dist/Components/Inputs/TimePanel.js +288 -0
- package/dist/Components/Inputs/TimePicker.d.ts +54 -0
- package/dist/Components/Inputs/TimePicker.js +240 -0
- package/dist/Components/Inputs/TreeView.d.ts +160 -0
- package/dist/Components/Inputs/TreeView.js +947 -0
- package/dist/Components/Layouts/MessageBox.d.ts +71 -0
- package/dist/Components/Layouts/MessageBox.js +104 -0
- package/dist/Components/Layouts/Popup.d.ts +92 -0
- package/dist/Components/Layouts/Popup.js +376 -0
- package/dist/Components/Layouts/PopupContext.d.ts +2 -0
- package/dist/Components/Layouts/PopupContext.js +4 -0
- package/dist/Components/Layouts/PopupDock.d.ts +22 -0
- package/dist/Components/Layouts/PopupDock.js +121 -0
- package/dist/Components/Layouts/PopupHost.d.ts +56 -0
- package/dist/Components/Layouts/PopupHost.js +163 -0
- package/dist/Components/Layouts/PopupRules.d.ts +30 -0
- package/dist/Components/Layouts/PopupRules.js +63 -0
- package/dist/Components/Layouts/ThemePicker.d.ts +13 -0
- package/dist/Components/Layouts/ThemePicker.js +22 -0
- package/dist/Components/Layouts/ThemeScript.d.ts +14 -0
- package/dist/Components/Layouts/ThemeScript.js +13 -0
- package/dist/Components/Layouts/ThemeSwitcher.d.ts +13 -0
- package/dist/Components/Layouts/ThemeSwitcher.js +49 -0
- package/dist/Components/Layouts/Toaster.d.ts +76 -0
- package/dist/Components/Layouts/Toaster.js +172 -0
- package/dist/Components/Viewers/DataTable.d.ts +25 -0
- package/dist/Components/Viewers/DataTable.js +596 -0
- package/dist/Components/Viewers/DataTableColumns.d.ts +28 -0
- package/dist/Components/Viewers/DataTableColumns.js +243 -0
- package/dist/Components/Viewers/DataTableParts.d.ts +138 -0
- package/dist/Components/Viewers/DataTableParts.js +157 -0
- package/dist/Components/Viewers/MarkdownView.d.ts +26 -0
- package/dist/Components/Viewers/MarkdownView.js +79 -0
- package/dist/Components/Viewers/RichTextView.d.ts +18 -0
- package/dist/Components/Viewers/RichTextView.js +17 -0
- package/dist/Helpers/AnimationHelpers.d.ts +6 -0
- package/dist/Helpers/AnimationHelpers.js +35 -0
- package/dist/Helpers/ApiClient.d.ts +96 -0
- package/dist/Helpers/ApiClient.js +200 -0
- package/dist/Helpers/ApiFormHelpers.d.ts +49 -0
- package/dist/Helpers/ApiFormHelpers.js +120 -0
- package/dist/Helpers/ApiModules.d.ts +131 -0
- package/dist/Helpers/ApiModules.js +195 -0
- package/dist/Helpers/ApiResponses.d.ts +51 -0
- package/dist/Helpers/ApiResponses.js +250 -0
- package/dist/Helpers/ApiRoutes.d.ts +140 -0
- package/dist/Helpers/ApiRoutes.js +183 -0
- package/dist/Helpers/ApiToasts.d.ts +21 -0
- package/dist/Helpers/ApiToasts.js +22 -0
- package/dist/Helpers/ChatBackend.d.ts +134 -0
- package/dist/Helpers/ChatBackend.js +332 -0
- package/dist/Helpers/ChatHelpers.d.ts +189 -0
- package/dist/Helpers/ChatHelpers.js +486 -0
- package/dist/Helpers/ChatHooks.d.ts +81 -0
- package/dist/Helpers/ChatHooks.js +175 -0
- package/dist/Helpers/ChatStore.d.ts +132 -0
- package/dist/Helpers/ChatStore.js +394 -0
- package/dist/Helpers/ChatSummaries.d.ts +39 -0
- package/dist/Helpers/ChatSummaries.js +118 -0
- package/dist/Helpers/ClassHelpers.d.ts +3 -0
- package/dist/Helpers/ClassHelpers.js +4 -0
- package/dist/Helpers/CrudBackend.d.ts +98 -0
- package/dist/Helpers/CrudBackend.js +214 -0
- package/dist/Helpers/CrudHelpers.d.ts +111 -0
- package/dist/Helpers/CrudHelpers.js +267 -0
- package/dist/Helpers/DateHelpers.d.ts +88 -0
- package/dist/Helpers/DateHelpers.js +363 -0
- package/dist/Helpers/DatePreferences.d.ts +14 -0
- package/dist/Helpers/DatePreferences.js +94 -0
- package/dist/Helpers/DateTimeHelpers.d.ts +87 -0
- package/dist/Helpers/DateTimeHelpers.js +286 -0
- package/dist/Helpers/DragHelpers.d.ts +129 -0
- package/dist/Helpers/DragHelpers.js +281 -0
- package/dist/Helpers/DropdownHelpers.d.ts +56 -0
- package/dist/Helpers/DropdownHelpers.js +180 -0
- package/dist/Helpers/ExcelBackend.d.ts +106 -0
- package/dist/Helpers/ExcelBackend.js +290 -0
- package/dist/Helpers/ExcelHelpers.d.ts +98 -0
- package/dist/Helpers/ExcelHelpers.js +302 -0
- package/dist/Helpers/FormDrafts.d.ts +18 -0
- package/dist/Helpers/FormDrafts.js +76 -0
- package/dist/Helpers/FormStore.d.ts +233 -0
- package/dist/Helpers/FormStore.js +752 -0
- package/dist/Helpers/InputParamsHelpers.d.ts +79 -0
- package/dist/Helpers/InputParamsHelpers.js +388 -0
- package/dist/Helpers/MarkdownEditing.d.ts +27 -0
- package/dist/Helpers/MarkdownEditing.js +250 -0
- package/dist/Helpers/MarkdownHelpers.d.ts +82 -0
- package/dist/Helpers/MarkdownHelpers.js +775 -0
- package/dist/Helpers/MessageBuilder.d.ts +74 -0
- package/dist/Helpers/MessageBuilder.js +252 -0
- package/dist/Helpers/NepaliCalendar.d.ts +25 -0
- package/dist/Helpers/NepaliCalendar.js +107 -0
- package/dist/Helpers/NumberHelpers.d.ts +71 -0
- package/dist/Helpers/NumberHelpers.js +202 -0
- package/dist/Helpers/Permissions.d.ts +62 -0
- package/dist/Helpers/Permissions.js +133 -0
- package/dist/Helpers/PopoverHelpers.d.ts +68 -0
- package/dist/Helpers/PopoverHelpers.js +195 -0
- package/dist/Helpers/RichTextHelpers.d.ts +77 -0
- package/dist/Helpers/RichTextHelpers.js +1072 -0
- package/dist/Helpers/RowsStore.d.ts +166 -0
- package/dist/Helpers/RowsStore.js +606 -0
- package/dist/Helpers/TableColumns.d.ts +47 -0
- package/dist/Helpers/TableColumns.js +282 -0
- package/dist/Helpers/TableExport.d.ts +30 -0
- package/dist/Helpers/TableExport.js +97 -0
- package/dist/Helpers/TableHelpers.d.ts +110 -0
- package/dist/Helpers/TableHelpers.js +301 -0
- package/dist/Helpers/TableStore.d.ts +142 -0
- package/dist/Helpers/TableStore.js +530 -0
- package/dist/Helpers/ThemeHelpers.d.ts +15 -0
- package/dist/Helpers/ThemeHelpers.js +16 -0
- package/dist/Helpers/TimeHelpers.d.ts +73 -0
- package/dist/Helpers/TimeHelpers.js +253 -0
- package/dist/Helpers/TreeStore.d.ts +188 -0
- package/dist/Helpers/TreeStore.js +577 -0
- package/dist/Helpers/ValidationHelpers.d.ts +124 -0
- package/dist/Helpers/ValidationHelpers.js +301 -0
- package/dist/Interfaces/ApiInterfaces.d.ts +174 -0
- package/dist/Interfaces/ApiInterfaces.js +30 -0
- package/dist/Interfaces/ChatInterfaces.d.ts +240 -0
- package/{src/sso-client.tsx → dist/Interfaces/ChatInterfaces.js} +1 -1
- package/dist/Interfaces/CrudInterfaces.d.ts +232 -0
- package/dist/Interfaces/CrudInterfaces.js +1 -0
- package/dist/Interfaces/DateInterfaces.d.ts +154 -0
- package/dist/Interfaces/DateInterfaces.js +29 -0
- package/dist/Interfaces/ExcelInterfaces.d.ts +215 -0
- package/dist/Interfaces/ExcelInterfaces.js +45 -0
- package/dist/Interfaces/FormInterfaces.d.ts +402 -0
- package/dist/Interfaces/FormInterfaces.js +1 -0
- package/dist/Interfaces/InputInterfaces.d.ts +141 -0
- package/dist/Interfaces/InputInterfaces.js +1 -0
- package/dist/Interfaces/MessageInterfaces.d.ts +111 -0
- package/dist/Interfaces/MessageInterfaces.js +5 -0
- package/dist/Interfaces/TableInterfaces.d.ts +351 -0
- package/dist/Interfaces/TableInterfaces.js +1 -0
- package/dist/Interfaces/ThemeInterfaces.d.ts +17 -0
- package/dist/Interfaces/ThemeInterfaces.js +17 -0
- package/dist/Interfaces/TypeInterfaces.d.ts +4 -0
- package/dist/Interfaces/TypeInterfaces.js +1 -0
- package/dist/Server.Index.d.ts +2 -0
- package/dist/Server.Index.js +5 -0
- package/dist/Services/ApiProxy.d.ts +32 -0
- package/dist/Services/ApiProxy.js +111 -0
- package/dist/Services/BrowserApi.d.ts +95 -0
- package/dist/Services/BrowserApi.js +129 -0
- package/dist/Services/ChatApi.d.ts +37 -0
- package/dist/Services/ChatApi.js +98 -0
- package/dist/Services/ExcelApi.d.ts +46 -0
- package/dist/Services/ExcelApi.js +196 -0
- package/dist/Services/ServerApi.d.ts +54 -0
- package/dist/Services/ServerApi.js +78 -0
- package/dist/Services/ThemeService.d.ts +17 -0
- package/dist/Services/ThemeService.js +83 -0
- package/dist/Shared.Index.d.ts +51 -0
- package/dist/Shared.Index.js +55 -0
- package/package.json +85 -33
- package/src/Styles/Nexus.Base.css +70 -0
- package/src/Styles/Nexus.Button.css +153 -0
- package/src/Styles/Nexus.Calendar.css +275 -0
- package/src/Styles/Nexus.Chat.css +1489 -0
- package/src/Styles/Nexus.Choice.css +345 -0
- package/src/Styles/Nexus.Crud.css +161 -0
- package/src/Styles/Nexus.DateTime.css +81 -0
- package/src/Styles/Nexus.Dropdown.css +774 -0
- package/src/Styles/Nexus.Editor.css +297 -0
- package/src/Styles/Nexus.Excel.css +370 -0
- package/src/Styles/Nexus.Form.css +321 -0
- package/src/Styles/Nexus.Index.css +36 -0
- package/src/Styles/Nexus.Input.css +637 -0
- package/src/Styles/Nexus.Markdown.css +265 -0
- package/src/Styles/Nexus.Menu.css +259 -0
- package/src/Styles/Nexus.Popup.css +731 -0
- package/src/Styles/Nexus.RichText.css +463 -0
- package/src/Styles/Nexus.Rows.css +596 -0
- package/src/Styles/Nexus.Slider.css +278 -0
- package/src/Styles/Nexus.Tab.Buttons.css +419 -0
- package/src/Styles/Nexus.Table.css +1296 -0
- package/src/Styles/Nexus.Theme.Picker.css +232 -0
- package/src/Styles/Nexus.Themes.css +194 -0
- package/src/Styles/Nexus.Time.css +147 -0
- package/src/Styles/Nexus.Toast.css +265 -0
- package/src/Styles/Nexus.Tokens.css +72 -0
- package/src/Styles/Nexus.Tree.css +435 -0
- package/src/api-services/authentication-service.tsx +0 -23
- package/src/api-services/preference-service.tsx +0 -5
- package/src/api-services/system-service.tsx +0 -29
- package/src/client.ts +0 -31
- package/src/components/documents/button.tsx +0 -133
- package/src/components/documents/icon-box.tsx +0 -93
- package/src/components/documents/page-title.tsx +0 -7
- package/src/components/documents/tab-button.tsx +0 -172
- package/src/components/documents/tag.tsx +0 -30
- package/src/components/index.js +0 -0
- package/src/components/inputs/checkbox-input.tsx +0 -66
- package/src/components/inputs/input-box.tsx +0 -48
- package/src/components/inputs/input-element.tsx +0 -65
- package/src/components/inputs/input-form.tsx +0 -164
- package/src/components/inputs/input.tsx +0 -181
- package/src/components/inputs/number-input.tsx +0 -108
- package/src/components/inputs/radiobox-input.tsx +0 -53
- package/src/components/inputs/textarea-input.tsx +0 -47
- package/src/components/inputs/textbox-input.tsx +0 -45
- package/src/components/layouts/global-dialogbox.tsx +0 -431
- package/src/components/layouts/global-layout.tsx +0 -64
- package/src/components/layouts/layout-helpers.tsx +0 -20
- package/src/components/layouts/panels/user-panel.tsx +0 -112
- package/src/components/layouts/utility-menu.tsx +0 -49
- package/src/components/panels/theme-panel.tsx +0 -46
- package/src/helpers/bitwise-helpers.tsx +0 -11
- package/src/helpers/browser-helpers.tsx +0 -156
- package/src/helpers/datasource-helpers.tsx +0 -99
- package/src/helpers/element-helpers.tsx +0 -123
- package/src/helpers/input-helpers.tsx +0 -74
- package/src/helpers/string-helpers.tsx +0 -28
- package/src/helpers/utility-helpers.tsx +0 -45
- package/src/helpers/validation-helpers.tsx +0 -302
- package/src/index.ts +0 -26
- package/src/interface.ts +0 -19
- package/src/interfaces/auth-token-interfaces.tsx +0 -6
- package/src/interfaces/browser-interfaces.tsx +0 -36
- package/src/interfaces/button-interfaces.tsx +0 -63
- package/src/interfaces/datasource-interfaces.tsx +0 -22
- package/src/interfaces/datatable-interfaces.tsx +0 -25
- package/src/interfaces/dialogbox-interfaces.tsx +0 -5
- package/src/interfaces/exception-interfaces.tsx +0 -99
- package/src/interfaces/http-interfaces.tsx +0 -129
- package/src/interfaces/icon-interfaces.tsx +0 -129
- package/src/interfaces/input-interfaces.tsx +0 -410
- package/src/interfaces/layout-interfaces.tsx +0 -191
- package/src/interfaces/menu-interfaces.tsx +0 -53
- package/src/interfaces/message-interfaces.tsx +0 -32
- package/src/interfaces/permission-interfaces.tsx +0 -9
- package/src/interfaces/storage-interfaces.tsx +0 -5
- package/src/interfaces/system-interfaces.tsx +0 -22
- package/src/interfaces/theme-interfaces.tsx +0 -123
- package/src/interfaces/type-interfaces.tsx +0 -28
- package/src/interfaces/user-interfaces.tsx +0 -47
- package/src/nexus-client.tsx +0 -21
- package/src/nexus.environments.tsx +0 -66
- package/src/proxy-api/proxy-backend.tsx +0 -60
- package/src/proxy-api/proxy-constants.tsx +0 -28
- package/src/proxy-api/proxy-helpers.tsx +0 -91
- package/src/proxy-api-client.tsx +0 -1
- package/src/proxy-api-server.tsx +0 -2
- package/src/services/http-client-services.tsx +0 -75
- package/src/services/http-services.tsx +0 -158
- package/src/services/loader-service.tsx +0 -185
- package/src/services/localstorage-service.tsx +0 -119
- package/src/services/message-services.tsx +0 -383
- package/src/services/theme-service.tsx +0 -163
- package/src/services/user-services.tsx +0 -10
- package/src/sso-config/auth-token-validation.ts +0 -16
- package/src/sso-config/callback-route.tsx +0 -35
- package/src/sso-config/cookie-encryption.ts +0 -51
- package/src/sso-config/cookie-helpers.tsx +0 -102
- package/src/sso-config/forgot-password-route.tsx +0 -36
- package/src/sso-config/oauth-callback-state.ts +0 -61
- package/src/sso-config/pkce-helpers.ts +0 -9
- package/src/sso-config/provider-complete-route.tsx +0 -18
- package/src/sso-config/redirect-context-actions.tsx +0 -45
- package/src/sso-config/redirect-context-helpers.tsx +0 -159
- package/src/sso-config/redirect-context-persist.tsx +0 -18
- package/src/sso-config/redirect-context-route.tsx +0 -45
- package/src/sso-config/refresh-route.tsx +0 -23
- package/src/sso-config/sign-in-route.tsx +0 -74
- package/src/sso-config/sign-out-route.tsx +0 -57
- package/src/sso-config/sign-up-route.tsx +0 -57
- package/src/sso-config/sso-backend-flow.ts +0 -38
- package/src/sso-config/sso-complete-route.tsx +0 -50
- package/src/sso-config/sso-config.ts +0 -59
- package/src/sso-config/sso-interfaces.tsx +0 -99
- package/src/sso-config/sso-response-helpers.tsx +0 -20
- package/src/sso-server.tsx +0 -21
- package/src/styles/nexus.animation.css +0 -269
- package/src/styles/nexus.core.css +0 -119
- package/src/styles/nexus.dialog.css +0 -144
- package/src/styles/nexus.grid-view.css +0 -42
- package/src/styles/nexus.icon.css +0 -51
- package/src/styles/nexus.input.css +0 -207
- package/src/styles/nexus.loader.css +0 -11
- package/src/styles/nexus.logic.css +0 -47
- package/src/styles/nexus.utility.css +0 -347
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { messageBox } from "../Components/Layouts/MessageBox.js";
|
|
3
|
+
import { toast } from "../Components/Layouts/Toaster.js";
|
|
4
|
+
import { apiCallContext } from "../Helpers/ApiClient.js";
|
|
5
|
+
import { getExcelBackend, readDownloadHeaders, readExcelResponse } from "../Helpers/ExcelBackend.js";
|
|
6
|
+
import { excelCount, excelExportWarning, excelText, saveExcelFile } from "../Helpers/ExcelHelpers.js";
|
|
7
|
+
import { buildMessage } from "../Helpers/MessageBuilder.js";
|
|
8
|
+
import { api, getApiCallSettings, getApiReader } from "./BrowserApi.js";
|
|
9
|
+
/* The settings, kept */
|
|
10
|
+
const settingsCache = new Map();
|
|
11
|
+
const cacheKey = (endpoint, options) => `${String(endpoint.module)}|${endpoint.path}|${JSON.stringify(options.params ?? null)}`;
|
|
12
|
+
/**
|
|
13
|
+
* The limits and the shape of the sheet. It is the same for everybody and changes once a release, so the first answer
|
|
14
|
+
* is kept for as long as the page lives - the backend says the same with a `Cache-Control` of an hour.
|
|
15
|
+
*/
|
|
16
|
+
export async function excelSettings(endpoints, options = {}) {
|
|
17
|
+
const key = cacheKey(endpoints.settings, options);
|
|
18
|
+
const kept = settingsCache.get(key);
|
|
19
|
+
if (kept)
|
|
20
|
+
return kept;
|
|
21
|
+
const asked = (async () => {
|
|
22
|
+
const answer = await api.get(endpoints.settings, { ...call(options), toast: options.toast === false ? false : { success: false } });
|
|
23
|
+
if (!answer.ok)
|
|
24
|
+
return answer;
|
|
25
|
+
return { ...answer, result: getExcelBackend().readSettings(answer.result) };
|
|
26
|
+
})();
|
|
27
|
+
settingsCache.set(key, asked);
|
|
28
|
+
// A failure is not worth keeping: the next offer of an import should ask again.
|
|
29
|
+
const answer = await asked;
|
|
30
|
+
if (!answer.ok)
|
|
31
|
+
settingsCache.delete(key);
|
|
32
|
+
return answer;
|
|
33
|
+
}
|
|
34
|
+
/** Forgets the kept settings, for a test or an app that changed what a sheet holds while it ran. */
|
|
35
|
+
export function clearExcelSettings() {
|
|
36
|
+
settingsCache.clear();
|
|
37
|
+
}
|
|
38
|
+
/* The template, and the export: the two downloads */
|
|
39
|
+
/** The template to fill in, as the backend built it, under the name the answer gives it. */
|
|
40
|
+
export async function downloadExcelTemplate(endpoints, options = {}) {
|
|
41
|
+
const limits = await excelSettings(endpoints, { signal: options.signal, params: options.params, toast: options.toast });
|
|
42
|
+
const name = limits.result?.templateFileName ?? "template.xlsx";
|
|
43
|
+
const answer = await download(endpoints.template, options, name);
|
|
44
|
+
if (answer.ok && answer.result)
|
|
45
|
+
saveExcelFile(answer.result);
|
|
46
|
+
return answer;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* An export of what the person has on screen: the search, the sort and the filters, sent to the model's own action.
|
|
50
|
+
* Not a file written from the rows the browser happens to hold - the backend writes every row the search leaves, up to
|
|
51
|
+
* its own limit, and says in the answer's headers what it left out.
|
|
52
|
+
*
|
|
53
|
+
* Over that limit the person is asked first, because a file that is quietly short is worse than one they chose.
|
|
54
|
+
*/
|
|
55
|
+
export async function exportExcel(endpoints, options = {}) {
|
|
56
|
+
const endpoint = endpoints.export;
|
|
57
|
+
if (!endpoint)
|
|
58
|
+
throw new Error("This model has no export endpoint: `excelEndpoints` was given `exportable: false`, or the app's own endpoints left `export` out.");
|
|
59
|
+
const limits = await excelSettings(endpoints, { signal: options.signal, params: options.params, toast: options.toast });
|
|
60
|
+
const subject = options.subject ?? limits.result?.subject ?? "row";
|
|
61
|
+
const limit = limits.result?.maxExportRows;
|
|
62
|
+
if (options.confirm !== false && limit !== undefined && options.rows !== undefined && options.rows > limit) {
|
|
63
|
+
const yes = await messageBox.confirm({
|
|
64
|
+
title: excelText("exportWarning"),
|
|
65
|
+
message: excelExportWarning(options.rows, limit, subject),
|
|
66
|
+
tone: "warning",
|
|
67
|
+
confirmLabel: `Export ${excelCount(limit, subject)}`,
|
|
68
|
+
});
|
|
69
|
+
if (!yes)
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
// The request is the model's own list request. A GET export carries it in the URL, a POST one in its body.
|
|
73
|
+
const request = getExcelBackend().exportRequest(options.query ?? {});
|
|
74
|
+
const isGet = endpoint.method === "GET";
|
|
75
|
+
const { query: _screen, ...rest } = options;
|
|
76
|
+
const answer = await download(endpoint, { ...rest, ...(isGet ? { query: toApiQuery(request) } : {}) }, `${subject}.xlsx`, isGet ? undefined : request);
|
|
77
|
+
if (!answer.ok || !answer.result)
|
|
78
|
+
return answer;
|
|
79
|
+
saveExcelFile(answer.result);
|
|
80
|
+
if (options.toast !== false) {
|
|
81
|
+
const note = answer.result.note;
|
|
82
|
+
const written = answer.result.rows === undefined ? undefined : excelCount(answer.result.rows, subject);
|
|
83
|
+
if (note)
|
|
84
|
+
toast.warning(written ? `${written} exported` : "Exported", { message: note });
|
|
85
|
+
else
|
|
86
|
+
toast.success(written ? `${written} exported` : "Exported", { message: answer.result.fileName });
|
|
87
|
+
}
|
|
88
|
+
return answer;
|
|
89
|
+
}
|
|
90
|
+
/* The two legs of an import */
|
|
91
|
+
/** The filled file read and judged, with nothing written. The rows it answers with are what an import sends back. */
|
|
92
|
+
export async function verifyExcelFile(endpoints, file, options = {}) {
|
|
93
|
+
const form = new FormData();
|
|
94
|
+
form.append(getExcelBackend().uploadField, file, file.name);
|
|
95
|
+
const answer = await api.post(endpoints.verify, form, { ...call(options), toast: options.toast === false ? false : { success: false } });
|
|
96
|
+
if (!answer.ok)
|
|
97
|
+
return answer;
|
|
98
|
+
return { ...answer, result: getExcelBackend().readVerify(answer.result) };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Writes the rows a verify answered with, as the person left them - the **rows**, never the file again, or every fix
|
|
102
|
+
* they made on screen would be lost. Every check runs again on the way in: what the browser sends is a row, not a
|
|
103
|
+
* decision.
|
|
104
|
+
*/
|
|
105
|
+
export async function importExcelRows(endpoints, rows, options = {}) {
|
|
106
|
+
const backend = getExcelBackend();
|
|
107
|
+
const answer = await api.post(endpoints.import, backend.importRequest(rows), { ...call(options), count: rows.length, toast: options.toast === false ? false : { success: false } });
|
|
108
|
+
// An import that wrote nothing at all is the one failure; it still answers with what it refused, where it says so.
|
|
109
|
+
return { ...answer, result: answer.result === undefined ? undefined : backend.readImport(answer.result) };
|
|
110
|
+
}
|
|
111
|
+
/* Inside */
|
|
112
|
+
/**
|
|
113
|
+
* A call's options. The reader is named here, as the last word only: the call's own comes first and the app's
|
|
114
|
+
* (`configureApi({ read })`) second, so nothing shadows an app that registered one - and if neither did,
|
|
115
|
+
* `readExcelResponse` reads the backend's `errorMessages`, which is where a refused import says why.
|
|
116
|
+
*/
|
|
117
|
+
function call(options) {
|
|
118
|
+
const { toast: _toast, ...rest } = options;
|
|
119
|
+
return { ...rest, read: options.read ?? getApiReader() ?? readExcelResponse };
|
|
120
|
+
}
|
|
121
|
+
/** A request object as query values: what a URL can carry, and nothing else. */
|
|
122
|
+
function toApiQuery(request) {
|
|
123
|
+
const query = {};
|
|
124
|
+
if (typeof request !== "object" || request === null)
|
|
125
|
+
return query;
|
|
126
|
+
for (const [key, value] of Object.entries(request)) {
|
|
127
|
+
if (value === undefined || value === null)
|
|
128
|
+
continue;
|
|
129
|
+
if (Array.isArray(value))
|
|
130
|
+
query[key] = value.filter(item => typeof item === "string" || typeof item === "number" || typeof item === "boolean");
|
|
131
|
+
else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value instanceof Date)
|
|
132
|
+
query[key] = value;
|
|
133
|
+
}
|
|
134
|
+
return query;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* A download: the bytes, and the headers that say what the file is. It is the one `fetch` here, so it asks the API
|
|
138
|
+
* layer for everything a call of its own would have carried.
|
|
139
|
+
*/
|
|
140
|
+
async function download(endpoint, options, fallbackName, body) {
|
|
141
|
+
const settings = getApiCallSettings();
|
|
142
|
+
const described = apiCallContext(endpoint, { ...options, method: endpoint.method });
|
|
143
|
+
const url = await api.url(endpoint, { params: options.params, query: options.query, body });
|
|
144
|
+
const asked = { target: endpoint, ...described, url, options };
|
|
145
|
+
const headers = { ...settings.headers?.(asked), ...options.headers };
|
|
146
|
+
const token = settings.token?.(asked);
|
|
147
|
+
if (token)
|
|
148
|
+
headers.Authorization = /^bearer /i.test(token) ? token : `Bearer ${token}`;
|
|
149
|
+
if (body !== undefined)
|
|
150
|
+
headers["Content-Type"] = "application/json";
|
|
151
|
+
let response;
|
|
152
|
+
try {
|
|
153
|
+
response = await fetch(url, {
|
|
154
|
+
method: endpoint.method,
|
|
155
|
+
headers,
|
|
156
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
157
|
+
...(settings.credentials ? { credentials: settings.credentials } : {}),
|
|
158
|
+
signal: options.signal,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
catch (failure) {
|
|
162
|
+
// The caller gave up: nothing is said, as a stopped call says nothing anywhere else either.
|
|
163
|
+
if (failure instanceof DOMException && failure.name === "AbortError")
|
|
164
|
+
return { ok: false, aborted: true };
|
|
165
|
+
return fail({ ok: false, network: true }, described, options);
|
|
166
|
+
}
|
|
167
|
+
if (!response.ok)
|
|
168
|
+
return fail(await readFailure(response, options), described, options);
|
|
169
|
+
const blob = await response.blob();
|
|
170
|
+
// A file of nothing is not a file. Some proxies answer 200 with an empty body when the backend went away.
|
|
171
|
+
if (blob.size === 0)
|
|
172
|
+
return fail({ ok: false, status: response.status, message: buildMessage("failure", described.context) || undefined }, described, options);
|
|
173
|
+
return { ok: true, status: response.status, result: readDownloadHeaders(response.headers, blob, fallbackName) };
|
|
174
|
+
}
|
|
175
|
+
/** A refused download answers in the backend's own envelope, not with a file, so it is read as any other answer is. */
|
|
176
|
+
async function readFailure(response, options) {
|
|
177
|
+
const read = options.read ?? getApiReader() ?? readExcelResponse;
|
|
178
|
+
const text = await response.text().catch(() => "");
|
|
179
|
+
let parsed = text;
|
|
180
|
+
if (text) {
|
|
181
|
+
try {
|
|
182
|
+
parsed = JSON.parse(text);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// Not JSON: an HTML error page, or nothing. The reader words it from the status.
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return read(parsed, response.status);
|
|
189
|
+
}
|
|
190
|
+
function fail(result, described, options) {
|
|
191
|
+
if (options.toast !== false && !result.aborted) {
|
|
192
|
+
const why = { ...described.context, status: result.status, network: result.network, timeout: result.timeout };
|
|
193
|
+
toast.error(buildMessage("failure", described.context) || excelText("verifyFailed"), { message: result.message || buildMessage("reason", why) || undefined });
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ApiCall, type ApiResponseReader } from "../Helpers/ApiClient.ts";
|
|
2
|
+
import type { ApiModuleValue, ApiResult } from "../Interfaces/ApiInterfaces.ts";
|
|
3
|
+
/** Options of a server call, on top of every call's options. */
|
|
4
|
+
export interface ServerApiOptions {
|
|
5
|
+
/** Keeps the answer in the Next.js data cache for this many seconds; `false` until a tag is revalidated. Default: not cached. */
|
|
6
|
+
revalidate?: number | false;
|
|
7
|
+
/** Cache tags, to refresh the answer with `revalidateTag`. Alone, they keep the answer until then. */
|
|
8
|
+
tags?: string[];
|
|
9
|
+
/** The bearer token for this call. Default: the `token` of `configureServerApi`; `null` sends none. */
|
|
10
|
+
token?: string | null;
|
|
11
|
+
}
|
|
12
|
+
/** How server calls behave. Where they go (each module's root) is the app's `ApiModules`. */
|
|
13
|
+
export interface ServerApiConfig {
|
|
14
|
+
/** The app's own address, for relative roots and URLs such as `/api/…`. Default: `URL_CURRENT` from the environment. */
|
|
15
|
+
origin?: string | (() => string | undefined | Promise<string | undefined>);
|
|
16
|
+
/** The user's token for every call, such as from the session cookie. */
|
|
17
|
+
token?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
18
|
+
/** Headers on every call, such as the tenant or branch. */
|
|
19
|
+
headers?: (call: ApiCall<ServerApiOptions>) => Record<string, string> | undefined | Promise<Record<string, string> | undefined>;
|
|
20
|
+
/** Milliseconds to wait for an answer. Default 60,000. */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Reads every answer, for a backend that does not answer as Nexus or ASP.NET Core do. Default `readApiResponse`.
|
|
24
|
+
* The same reader the browser is given in `configureApi`, so `api` and `serverApi` read one envelope.
|
|
25
|
+
*/
|
|
26
|
+
read?: ApiResponseReader<ServerApiOptions>;
|
|
27
|
+
/** After every answer. Default: logs network failures, timeouts, and 5xx answers with `console.error`. */
|
|
28
|
+
onResult?: (result: ApiResult, call: ApiCall<ServerApiOptions>) => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sets up `serverApi` and the proxy. Call it in a server module that the calls import; later calls change only the
|
|
32
|
+
* settings they name. Nothing is needed when the modules' roots are absolute and calls need no token.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* configureServerApi({ token: async () => (await cookies()).get("access_token")?.value });
|
|
36
|
+
*/
|
|
37
|
+
export declare function configureServerApi(config: ServerApiConfig): void;
|
|
38
|
+
/**
|
|
39
|
+
* A module's absolute root URL on the server, from the app's `ApiModules`. Throws "The Reservation API address is not
|
|
40
|
+
* set (API_RESERVATION)." when it is missing. `origin` resolves a relative root, such as the proxy's request origin.
|
|
41
|
+
*/
|
|
42
|
+
export declare function serverModuleRoot(module: ApiModuleValue, origin?: string): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Calls APIs from the server. Import it from `nexus-shared/server`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // A server component
|
|
48
|
+
* const rooms = await serverApi.get<Room[]>(ROOMS.listing, { revalidate: 60, tags: ["rooms"] });
|
|
49
|
+
* if (!rooms.ok) return <p>{rooms.message}</p>;
|
|
50
|
+
*
|
|
51
|
+
* // Or let the error boundary show it
|
|
52
|
+
* const room = unwrapApiResult(await serverApi.get<Room>(ROOMS.details, { params: { id } }));
|
|
53
|
+
*/
|
|
54
|
+
export declare const serverApi: import("../Shared.Index.ts").ApiClient<ServerApiOptions>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createApiClient } from "../Helpers/ApiClient.js";
|
|
2
|
+
import { describeEndpoint, getApiModules, readEnvironment } from "../Helpers/ApiModules.js";
|
|
3
|
+
import { joinUrl } from "../Helpers/ApiRoutes.js";
|
|
4
|
+
let settings = {};
|
|
5
|
+
/**
|
|
6
|
+
* Sets up `serverApi` and the proxy. Call it in a server module that the calls import; later calls change only the
|
|
7
|
+
* settings they name. Nothing is needed when the modules' roots are absolute and calls need no token.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* configureServerApi({ token: async () => (await cookies()).get("access_token")?.value });
|
|
11
|
+
*/
|
|
12
|
+
export function configureServerApi(config) {
|
|
13
|
+
settings = { ...settings, ...config };
|
|
14
|
+
}
|
|
15
|
+
async function appOrigin() {
|
|
16
|
+
const value = typeof settings.origin === "function" ? await settings.origin() : settings.origin;
|
|
17
|
+
return value || readEnvironment("URL_CURRENT");
|
|
18
|
+
}
|
|
19
|
+
async function absolute(url, fallbackOrigin) {
|
|
20
|
+
if (/^https?:\/\//i.test(url))
|
|
21
|
+
return url;
|
|
22
|
+
const origin = fallbackOrigin ?? (await appOrigin());
|
|
23
|
+
if (!origin)
|
|
24
|
+
throw new Error(`"${url}" is relative, and the app's address is not set (URL_CURRENT).`);
|
|
25
|
+
return new URL(url.startsWith("/") ? url : `/${url}`, origin).toString();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A module's absolute root URL on the server, from the app's `ApiModules`. Throws "The Reservation API address is not
|
|
29
|
+
* set (API_RESERVATION)." when it is missing. `origin` resolves a relative root, such as the proxy's request origin.
|
|
30
|
+
*/
|
|
31
|
+
export async function serverModuleRoot(module, origin) {
|
|
32
|
+
return absolute(await getApiModules().serverUrl(module), origin);
|
|
33
|
+
}
|
|
34
|
+
/** Where a call went, for logs: the module and path, never the query (it may hold what a user searched for). */
|
|
35
|
+
function describeCall(call) {
|
|
36
|
+
const where = call.url ? call.url.split("?")[0] : call.endpoint ? describeEndpoint(call.endpoint) : String(call.target);
|
|
37
|
+
return `${call.method} ${where}`;
|
|
38
|
+
}
|
|
39
|
+
function logFailure(result, call) {
|
|
40
|
+
if (result.ok || result.aborted)
|
|
41
|
+
return;
|
|
42
|
+
const status = result.status;
|
|
43
|
+
if (result.network || result.timeout || status === undefined || status >= 500)
|
|
44
|
+
console.error(`[serverApi] ${describeCall(call)}: ${status ?? ""} ${result.message ?? ""}`.replace(/\s+/g, " ").trim());
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Calls APIs from the server. Import it from `nexus-shared/server`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // A server component
|
|
51
|
+
* const rooms = await serverApi.get<Room[]>(ROOMS.listing, { revalidate: 60, tags: ["rooms"] });
|
|
52
|
+
* if (!rooms.ok) return <p>{rooms.message}</p>;
|
|
53
|
+
*
|
|
54
|
+
* // Or let the error boundary show it
|
|
55
|
+
* const room = unwrapApiResult(await serverApi.get<Room>(ROOMS.details, { params: { id } }));
|
|
56
|
+
*/
|
|
57
|
+
export const serverApi = createApiClient({
|
|
58
|
+
resolveUrl: async (endpoint, path) => joinUrl(await serverModuleRoot(endpoint.module), path),
|
|
59
|
+
resolveTarget: url => absolute(url),
|
|
60
|
+
headers: call => settings.headers?.(call),
|
|
61
|
+
token: call => (call.options.token !== undefined ? call.options.token : settings.token?.()),
|
|
62
|
+
get timeout() {
|
|
63
|
+
return settings.timeout;
|
|
64
|
+
},
|
|
65
|
+
get read() {
|
|
66
|
+
return settings.read;
|
|
67
|
+
},
|
|
68
|
+
prepare(init, call) {
|
|
69
|
+
const { revalidate, tags } = call.options;
|
|
70
|
+
// Next.js reads `next` and `cache` on a server fetch; `no-store` with `revalidate` would cancel both.
|
|
71
|
+
if (revalidate !== undefined)
|
|
72
|
+
return { ...init, next: { revalidate, ...(tags && { tags }) } };
|
|
73
|
+
if (tags)
|
|
74
|
+
return { ...init, cache: "force-cache", next: { tags } };
|
|
75
|
+
return { ...init, cache: "no-store" };
|
|
76
|
+
},
|
|
77
|
+
onResult: (result, call) => (settings.onResult ?? logFailure)(result, call),
|
|
78
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ThemeMode } from "../Interfaces/ThemeInterfaces.ts";
|
|
2
|
+
export interface ThemeState {
|
|
3
|
+
/** The active theme id. */
|
|
4
|
+
theme: string;
|
|
5
|
+
/** The chosen mode, which may be `system`. */
|
|
6
|
+
mode: ThemeMode;
|
|
7
|
+
/** The mode actually shown. */
|
|
8
|
+
resolvedMode: "light" | "dark";
|
|
9
|
+
setTheme: (theme: string) => void;
|
|
10
|
+
setMode: (mode: ThemeMode) => void;
|
|
11
|
+
}
|
|
12
|
+
/** Switches the theme on this page and saves it for the next visit. */
|
|
13
|
+
export declare function setTheme(theme: string): void;
|
|
14
|
+
/** Switches light, dark, or system on this page and saves it for the next visit. */
|
|
15
|
+
export declare function setThemeMode(mode: ThemeMode): void;
|
|
16
|
+
/** The current theme and mode, and functions to change them. */
|
|
17
|
+
export declare function useTheme(): ThemeState;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { THEME_ID_PATTERN } from "../Helpers/ThemeHelpers.js";
|
|
4
|
+
import { DEFAULT_THEME, THEME_ATTRIBUTE, THEME_MODE_ATTRIBUTE, THEME_MODE_STORAGE_KEY, THEME_STORAGE_KEY, } from "../Interfaces/ThemeInterfaces.js";
|
|
5
|
+
const DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
6
|
+
// Before hydration there is no document; the real values follow right after.
|
|
7
|
+
const SERVER_SNAPSHOT = `${DEFAULT_THEME} system light`;
|
|
8
|
+
// Colors switch at once, instead of every button and border running its own transition.
|
|
9
|
+
function withoutTransitions(change) {
|
|
10
|
+
const style = document.createElement("style");
|
|
11
|
+
style.textContent = "*,*::before,*::after{transition:none!important}";
|
|
12
|
+
document.head.appendChild(style);
|
|
13
|
+
change();
|
|
14
|
+
void window.getComputedStyle(document.body).color;
|
|
15
|
+
window.setTimeout(() => style.remove(), 1);
|
|
16
|
+
}
|
|
17
|
+
function save(key, value) {
|
|
18
|
+
try {
|
|
19
|
+
localStorage.setItem(key, value);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Storage blocked (private mode, for example): the choice lasts until the page reloads.
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function applyTheme(theme) {
|
|
26
|
+
withoutTransitions(() => document.documentElement.setAttribute(THEME_ATTRIBUTE, theme));
|
|
27
|
+
}
|
|
28
|
+
function applyMode(mode) {
|
|
29
|
+
const root = document.documentElement;
|
|
30
|
+
withoutTransitions(() => (mode === "system" ? root.removeAttribute(THEME_MODE_ATTRIBUTE) : root.setAttribute(THEME_MODE_ATTRIBUTE, mode)));
|
|
31
|
+
}
|
|
32
|
+
/** Switches the theme on this page and saves it for the next visit. */
|
|
33
|
+
export function setTheme(theme) {
|
|
34
|
+
if (!THEME_ID_PATTERN.test(theme))
|
|
35
|
+
return;
|
|
36
|
+
applyTheme(theme);
|
|
37
|
+
save(THEME_STORAGE_KEY, theme);
|
|
38
|
+
}
|
|
39
|
+
/** Switches light, dark, or system on this page and saves it for the next visit. */
|
|
40
|
+
export function setThemeMode(mode) {
|
|
41
|
+
applyMode(mode);
|
|
42
|
+
save(THEME_MODE_STORAGE_KEY, mode);
|
|
43
|
+
}
|
|
44
|
+
function readSnapshot() {
|
|
45
|
+
const root = document.documentElement;
|
|
46
|
+
const theme = root.getAttribute(THEME_ATTRIBUTE) || DEFAULT_THEME;
|
|
47
|
+
const attribute = root.getAttribute(THEME_MODE_ATTRIBUTE);
|
|
48
|
+
const mode = attribute === "light" || attribute === "dark" ? attribute : "system";
|
|
49
|
+
const resolved = mode === "system" ? (window.matchMedia(DARK_QUERY).matches ? "dark" : "light") : mode;
|
|
50
|
+
return `${theme} ${mode} ${resolved}`;
|
|
51
|
+
}
|
|
52
|
+
// The attributes on <html> are the source of truth, so every picker on the page stays in step,
|
|
53
|
+
// including changes made by the system setting or in another tab.
|
|
54
|
+
function subscribe(onChange) {
|
|
55
|
+
const observer = new MutationObserver(onChange);
|
|
56
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: [THEME_ATTRIBUTE, THEME_MODE_ATTRIBUTE] });
|
|
57
|
+
const media = window.matchMedia(DARK_QUERY);
|
|
58
|
+
media.addEventListener("change", onChange);
|
|
59
|
+
const onStorage = (event) => {
|
|
60
|
+
if (event.key === THEME_STORAGE_KEY && event.newValue && THEME_ID_PATTERN.test(event.newValue))
|
|
61
|
+
applyTheme(event.newValue);
|
|
62
|
+
if (event.key === THEME_MODE_STORAGE_KEY && (event.newValue === "light" || event.newValue === "dark" || event.newValue === "system")) {
|
|
63
|
+
applyMode(event.newValue);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
window.addEventListener("storage", onStorage);
|
|
67
|
+
return () => {
|
|
68
|
+
observer.disconnect();
|
|
69
|
+
media.removeEventListener("change", onChange);
|
|
70
|
+
window.removeEventListener("storage", onStorage);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** The current theme and mode, and functions to change them. */
|
|
74
|
+
export function useTheme() {
|
|
75
|
+
const [theme, mode, resolvedMode] = useSyncExternalStore(subscribe, readSnapshot, () => SERVER_SNAPSHOT).split(" ");
|
|
76
|
+
return {
|
|
77
|
+
theme: theme ?? DEFAULT_THEME,
|
|
78
|
+
mode: (mode ?? "system"),
|
|
79
|
+
resolvedMode: resolvedMode === "dark" ? "dark" : "light",
|
|
80
|
+
setTheme,
|
|
81
|
+
setMode: setThemeMode,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export * from "./Components/Documents/Button.tsx";
|
|
2
|
+
export * from "./Components/Inputs/Field.tsx";
|
|
3
|
+
export * from "./Components/Layouts/ThemeScript.tsx";
|
|
4
|
+
export * from "./Components/Viewers/MarkdownView.tsx";
|
|
5
|
+
export * from "./Components/Viewers/RichTextView.tsx";
|
|
6
|
+
export * from "./Helpers/ApiClient.ts";
|
|
7
|
+
export * from "./Helpers/ApiFormHelpers.ts";
|
|
8
|
+
export * from "./Helpers/ApiModules.ts";
|
|
9
|
+
export * from "./Helpers/ApiResponses.ts";
|
|
10
|
+
export * from "./Helpers/ApiRoutes.ts";
|
|
11
|
+
export * from "./Helpers/ApiToasts.ts";
|
|
12
|
+
export * from "./Helpers/ChatBackend.ts";
|
|
13
|
+
export * from "./Helpers/ChatHelpers.ts";
|
|
14
|
+
export * from "./Helpers/ChatStore.ts";
|
|
15
|
+
export * from "./Helpers/ChatSummaries.ts";
|
|
16
|
+
export * from "./Helpers/ClassHelpers.ts";
|
|
17
|
+
export * from "./Helpers/CrudBackend.ts";
|
|
18
|
+
export * from "./Helpers/CrudHelpers.ts";
|
|
19
|
+
export * from "./Helpers/DateHelpers.ts";
|
|
20
|
+
export * from "./Helpers/DateTimeHelpers.ts";
|
|
21
|
+
export * from "./Helpers/DropdownHelpers.ts";
|
|
22
|
+
export * from "./Helpers/ExcelBackend.ts";
|
|
23
|
+
export * from "./Helpers/ExcelHelpers.ts";
|
|
24
|
+
export * from "./Helpers/FormDrafts.ts";
|
|
25
|
+
export * from "./Helpers/FormStore.ts";
|
|
26
|
+
export * from "./Helpers/InputParamsHelpers.ts";
|
|
27
|
+
export * from "./Helpers/MarkdownEditing.ts";
|
|
28
|
+
export * from "./Helpers/MarkdownHelpers.ts";
|
|
29
|
+
export * from "./Helpers/MessageBuilder.ts";
|
|
30
|
+
export * from "./Helpers/NepaliCalendar.ts";
|
|
31
|
+
export * from "./Helpers/NumberHelpers.ts";
|
|
32
|
+
export * from "./Helpers/Permissions.ts";
|
|
33
|
+
export * from "./Helpers/RichTextHelpers.ts";
|
|
34
|
+
export * from "./Helpers/RowsStore.ts";
|
|
35
|
+
export * from "./Helpers/TableHelpers.ts";
|
|
36
|
+
export * from "./Helpers/TableStore.ts";
|
|
37
|
+
export * from "./Helpers/ThemeHelpers.ts";
|
|
38
|
+
export * from "./Helpers/TimeHelpers.ts";
|
|
39
|
+
export * from "./Helpers/TreeStore.ts";
|
|
40
|
+
export * from "./Helpers/ValidationHelpers.ts";
|
|
41
|
+
export * from "./Interfaces/ApiInterfaces.ts";
|
|
42
|
+
export * from "./Interfaces/ChatInterfaces.ts";
|
|
43
|
+
export * from "./Interfaces/CrudInterfaces.ts";
|
|
44
|
+
export * from "./Interfaces/DateInterfaces.ts";
|
|
45
|
+
export * from "./Interfaces/ExcelInterfaces.ts";
|
|
46
|
+
export * from "./Interfaces/FormInterfaces.ts";
|
|
47
|
+
export * from "./Interfaces/InputInterfaces.ts";
|
|
48
|
+
export * from "./Interfaces/MessageInterfaces.ts";
|
|
49
|
+
export * from "./Interfaces/TableInterfaces.ts";
|
|
50
|
+
export * from "./Interfaces/ThemeInterfaces.ts";
|
|
51
|
+
export * from "./Interfaces/TypeInterfaces.ts";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Works everywhere: server components, client components, and plain TypeScript.
|
|
2
|
+
// Components
|
|
3
|
+
export * from "./Components/Documents/Button.js";
|
|
4
|
+
export * from "./Components/Inputs/Field.js";
|
|
5
|
+
export * from "./Components/Layouts/ThemeScript.js";
|
|
6
|
+
export * from "./Components/Viewers/MarkdownView.js";
|
|
7
|
+
export * from "./Components/Viewers/RichTextView.js";
|
|
8
|
+
// Helpers
|
|
9
|
+
export * from "./Helpers/ApiClient.js";
|
|
10
|
+
export * from "./Helpers/ApiFormHelpers.js";
|
|
11
|
+
export * from "./Helpers/ApiModules.js";
|
|
12
|
+
export * from "./Helpers/ApiResponses.js";
|
|
13
|
+
export * from "./Helpers/ApiRoutes.js";
|
|
14
|
+
export * from "./Helpers/ApiToasts.js";
|
|
15
|
+
export * from "./Helpers/ChatBackend.js";
|
|
16
|
+
export * from "./Helpers/ChatHelpers.js";
|
|
17
|
+
export * from "./Helpers/ChatStore.js";
|
|
18
|
+
export * from "./Helpers/ChatSummaries.js";
|
|
19
|
+
export * from "./Helpers/ClassHelpers.js";
|
|
20
|
+
export * from "./Helpers/CrudBackend.js";
|
|
21
|
+
export * from "./Helpers/CrudHelpers.js";
|
|
22
|
+
export * from "./Helpers/DateHelpers.js";
|
|
23
|
+
export * from "./Helpers/DateTimeHelpers.js";
|
|
24
|
+
export * from "./Helpers/DropdownHelpers.js";
|
|
25
|
+
export * from "./Helpers/ExcelBackend.js";
|
|
26
|
+
export * from "./Helpers/ExcelHelpers.js";
|
|
27
|
+
export * from "./Helpers/FormDrafts.js";
|
|
28
|
+
export * from "./Helpers/FormStore.js";
|
|
29
|
+
export * from "./Helpers/InputParamsHelpers.js";
|
|
30
|
+
export * from "./Helpers/MarkdownEditing.js";
|
|
31
|
+
export * from "./Helpers/MarkdownHelpers.js";
|
|
32
|
+
export * from "./Helpers/MessageBuilder.js";
|
|
33
|
+
export * from "./Helpers/NepaliCalendar.js";
|
|
34
|
+
export * from "./Helpers/NumberHelpers.js";
|
|
35
|
+
export * from "./Helpers/Permissions.js";
|
|
36
|
+
export * from "./Helpers/RichTextHelpers.js";
|
|
37
|
+
export * from "./Helpers/RowsStore.js";
|
|
38
|
+
export * from "./Helpers/TableHelpers.js";
|
|
39
|
+
export * from "./Helpers/TableStore.js";
|
|
40
|
+
export * from "./Helpers/ThemeHelpers.js";
|
|
41
|
+
export * from "./Helpers/TimeHelpers.js";
|
|
42
|
+
export * from "./Helpers/TreeStore.js";
|
|
43
|
+
export * from "./Helpers/ValidationHelpers.js";
|
|
44
|
+
// Interfaces
|
|
45
|
+
export * from "./Interfaces/ApiInterfaces.js";
|
|
46
|
+
export * from "./Interfaces/ChatInterfaces.js";
|
|
47
|
+
export * from "./Interfaces/CrudInterfaces.js";
|
|
48
|
+
export * from "./Interfaces/DateInterfaces.js";
|
|
49
|
+
export * from "./Interfaces/ExcelInterfaces.js";
|
|
50
|
+
export * from "./Interfaces/FormInterfaces.js";
|
|
51
|
+
export * from "./Interfaces/InputInterfaces.js";
|
|
52
|
+
export * from "./Interfaces/MessageInterfaces.js";
|
|
53
|
+
export * from "./Interfaces/TableInterfaces.js";
|
|
54
|
+
export * from "./Interfaces/ThemeInterfaces.js";
|
|
55
|
+
export * from "./Interfaces/TypeInterfaces.js";
|
package/package.json
CHANGED
|
@@ -1,33 +1,85 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "nexus-shared",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Nexus
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "nexus-shared",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "The Nexus component library for React and Next.js: params-driven inputs and forms, a data table with a CRUD on top, popups and toasts, an API layer with permissions, Markdown and rich text editors, and 7 themes in light and dark.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"nextjs",
|
|
8
|
+
"components",
|
|
9
|
+
"ui",
|
|
10
|
+
"forms",
|
|
11
|
+
"datatable",
|
|
12
|
+
"crud",
|
|
13
|
+
"inputs",
|
|
14
|
+
"design-system",
|
|
15
|
+
"typescript",
|
|
16
|
+
"nepali-calendar",
|
|
17
|
+
"nexus"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Bijay Adhikari",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"*.css"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/Shared.Index.d.ts",
|
|
28
|
+
"default": "./dist/Shared.Index.js"
|
|
29
|
+
},
|
|
30
|
+
"./client": {
|
|
31
|
+
"types": "./dist/Client.Index.d.ts",
|
|
32
|
+
"default": "./dist/Client.Index.js"
|
|
33
|
+
},
|
|
34
|
+
"./server": {
|
|
35
|
+
"types": "./dist/Server.Index.d.ts",
|
|
36
|
+
"default": "./dist/Server.Index.js"
|
|
37
|
+
},
|
|
38
|
+
"./styles.css": "./src/Styles/Nexus.Index.css",
|
|
39
|
+
"./package.json": "./package.json"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"src/Styles",
|
|
44
|
+
"CHANGELOG.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.build.json",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
49
|
+
"test": "node scripts/test-all.mjs",
|
|
50
|
+
"check:themes": "node scripts/check-themes.mjs",
|
|
51
|
+
"test:api": "node scripts/test-api.mts",
|
|
52
|
+
"test:chat": "node scripts/test-chat.mts",
|
|
53
|
+
"test:dates": "node scripts/test-date-helpers.mts",
|
|
54
|
+
"test:datetimes": "node scripts/test-datetime-helpers.mts",
|
|
55
|
+
"test:drag": "node scripts/test-drag-helpers.mts",
|
|
56
|
+
"test:excel": "node scripts/test-excel.mts",
|
|
57
|
+
"test:dropdown": "node scripts/test-dropdown-helpers.mts",
|
|
58
|
+
"test:forms": "node scripts/test-form-store.mts",
|
|
59
|
+
"test:markdown": "node scripts/test-markdown.mts",
|
|
60
|
+
"test:numbers": "node scripts/test-number-helpers.mts",
|
|
61
|
+
"test:popups": "node scripts/test-popup-rules.mts",
|
|
62
|
+
"test:richtext": "node scripts/test-richtext.mts",
|
|
63
|
+
"test:rows": "node scripts/test-rows-store.mts",
|
|
64
|
+
"test:table": "node scripts/test-table.mts",
|
|
65
|
+
"test:times": "node scripts/test-time-helpers.mts",
|
|
66
|
+
"test:tree": "node scripts/test-tree-store.mts",
|
|
67
|
+
"test:types": "tsc -p scripts/type-checks/tsconfig.json"
|
|
68
|
+
},
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"nexus-icons": "^1.1.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"react": ">=19",
|
|
74
|
+
"react-dom": ">=19"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@types/react": "19.3.0"
|
|
78
|
+
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">=20.9"
|
|
81
|
+
},
|
|
82
|
+
"publishConfig": {
|
|
83
|
+
"access": "public"
|
|
84
|
+
}
|
|
85
|
+
}
|