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,55 @@
|
|
|
1
|
+
export * from "./Components/Chats/Chat.tsx";
|
|
2
|
+
export * from "./Components/Chats/ChatButton.tsx";
|
|
3
|
+
export * from "./Components/Chats/ChatComposer.tsx";
|
|
4
|
+
export * from "./Components/Chats/ChatConversations.tsx";
|
|
5
|
+
export * from "./Components/Chats/ChatPanel.tsx";
|
|
6
|
+
export * from "./Components/Chats/ChatParts.tsx";
|
|
7
|
+
export * from "./Components/Chats/ChatThread.tsx";
|
|
8
|
+
export * from "./Components/Documents/Menu.tsx";
|
|
9
|
+
export * from "./Components/Documents/SplitButton.tsx";
|
|
10
|
+
export * from "./Components/Documents/TabButtons.tsx";
|
|
11
|
+
export * from "./Components/Forms/ApiForm.tsx";
|
|
12
|
+
export * from "./Components/Forms/Crud.tsx";
|
|
13
|
+
export * from "./Components/Forms/CrudParts.tsx";
|
|
14
|
+
export * from "./Components/Forms/ExcelImport.tsx";
|
|
15
|
+
export * from "./Components/Forms/Form.tsx";
|
|
16
|
+
export * from "./Components/Forms/SubmitForm.tsx";
|
|
17
|
+
export * from "./Components/Inputs/Calendar.tsx";
|
|
18
|
+
export * from "./Components/Inputs/CheckBox.tsx";
|
|
19
|
+
export * from "./Components/Inputs/CheckBoxGroup.tsx";
|
|
20
|
+
export * from "./Components/Inputs/DatePicker.tsx";
|
|
21
|
+
export * from "./Components/Inputs/DateRangePicker.tsx";
|
|
22
|
+
export * from "./Components/Inputs/DateTimePicker.tsx";
|
|
23
|
+
export * from "./Components/Inputs/Dropdown.tsx";
|
|
24
|
+
export * from "./Components/Inputs/GroupForm.tsx";
|
|
25
|
+
export * from "./Components/Inputs/InputRenderer.tsx";
|
|
26
|
+
export * from "./Components/Inputs/MarkdownEditor.tsx";
|
|
27
|
+
export * from "./Components/Inputs/NumberBox.tsx";
|
|
28
|
+
export * from "./Components/Inputs/RadioGroup.tsx";
|
|
29
|
+
export * from "./Components/Inputs/ReadOnlyNotice.tsx";
|
|
30
|
+
export * from "./Components/Inputs/RichTextEditor.tsx";
|
|
31
|
+
export * from "./Components/Inputs/Slider.tsx";
|
|
32
|
+
export * from "./Components/Inputs/TabularForm.tsx";
|
|
33
|
+
export * from "./Components/Inputs/TextArea.tsx";
|
|
34
|
+
export * from "./Components/Inputs/TextBox.tsx";
|
|
35
|
+
export * from "./Components/Inputs/TimePanel.tsx";
|
|
36
|
+
export * from "./Components/Inputs/TimePicker.tsx";
|
|
37
|
+
export * from "./Components/Inputs/TreeView.tsx";
|
|
38
|
+
export * from "./Components/Layouts/MessageBox.tsx";
|
|
39
|
+
export * from "./Components/Layouts/Popup.tsx";
|
|
40
|
+
export * from "./Components/Layouts/PopupDock.tsx";
|
|
41
|
+
export * from "./Components/Layouts/PopupHost.tsx";
|
|
42
|
+
export * from "./Components/Layouts/PopupRules.ts";
|
|
43
|
+
export * from "./Components/Layouts/ThemePicker.tsx";
|
|
44
|
+
export * from "./Components/Layouts/ThemeSwitcher.tsx";
|
|
45
|
+
export * from "./Components/Layouts/Toaster.tsx";
|
|
46
|
+
export * from "./Components/Viewers/DataTable.tsx";
|
|
47
|
+
export * from "./Components/Viewers/DataTableParts.tsx";
|
|
48
|
+
export * from "./Helpers/ChatHooks.ts";
|
|
49
|
+
export * from "./Helpers/DatePreferences.ts";
|
|
50
|
+
export * from "./Helpers/DragHelpers.ts";
|
|
51
|
+
export * from "./Helpers/PopoverHelpers.ts";
|
|
52
|
+
export * from "./Services/BrowserApi.ts";
|
|
53
|
+
export * from "./Services/ChatApi.ts";
|
|
54
|
+
export * from "./Services/ExcelApi.ts";
|
|
55
|
+
export * from "./Services/ThemeService.ts";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Client components and browser services: files here start with "use client" or use browser APIs.
|
|
2
|
+
// Import from "nexus-shared/client".
|
|
3
|
+
// Components
|
|
4
|
+
export * from "./Components/Chats/Chat.js";
|
|
5
|
+
export * from "./Components/Chats/ChatButton.js";
|
|
6
|
+
export * from "./Components/Chats/ChatComposer.js";
|
|
7
|
+
export * from "./Components/Chats/ChatConversations.js";
|
|
8
|
+
export * from "./Components/Chats/ChatPanel.js";
|
|
9
|
+
export * from "./Components/Chats/ChatParts.js";
|
|
10
|
+
export * from "./Components/Chats/ChatThread.js";
|
|
11
|
+
export * from "./Components/Documents/Menu.js";
|
|
12
|
+
export * from "./Components/Documents/SplitButton.js";
|
|
13
|
+
export * from "./Components/Documents/TabButtons.js";
|
|
14
|
+
export * from "./Components/Forms/ApiForm.js";
|
|
15
|
+
export * from "./Components/Forms/Crud.js";
|
|
16
|
+
export * from "./Components/Forms/CrudParts.js";
|
|
17
|
+
export * from "./Components/Forms/ExcelImport.js";
|
|
18
|
+
export * from "./Components/Forms/Form.js";
|
|
19
|
+
export * from "./Components/Forms/SubmitForm.js";
|
|
20
|
+
export * from "./Components/Inputs/Calendar.js";
|
|
21
|
+
export * from "./Components/Inputs/CheckBox.js";
|
|
22
|
+
export * from "./Components/Inputs/CheckBoxGroup.js";
|
|
23
|
+
export * from "./Components/Inputs/DatePicker.js";
|
|
24
|
+
export * from "./Components/Inputs/DateRangePicker.js";
|
|
25
|
+
export * from "./Components/Inputs/DateTimePicker.js";
|
|
26
|
+
export * from "./Components/Inputs/Dropdown.js";
|
|
27
|
+
export * from "./Components/Inputs/GroupForm.js";
|
|
28
|
+
export * from "./Components/Inputs/InputRenderer.js";
|
|
29
|
+
export * from "./Components/Inputs/MarkdownEditor.js";
|
|
30
|
+
export * from "./Components/Inputs/NumberBox.js";
|
|
31
|
+
export * from "./Components/Inputs/RadioGroup.js";
|
|
32
|
+
export * from "./Components/Inputs/ReadOnlyNotice.js";
|
|
33
|
+
export * from "./Components/Inputs/RichTextEditor.js";
|
|
34
|
+
export * from "./Components/Inputs/Slider.js";
|
|
35
|
+
export * from "./Components/Inputs/TabularForm.js";
|
|
36
|
+
export * from "./Components/Inputs/TextArea.js";
|
|
37
|
+
export * from "./Components/Inputs/TextBox.js";
|
|
38
|
+
export * from "./Components/Inputs/TimePanel.js";
|
|
39
|
+
export * from "./Components/Inputs/TimePicker.js";
|
|
40
|
+
export * from "./Components/Inputs/TreeView.js";
|
|
41
|
+
export * from "./Components/Layouts/MessageBox.js";
|
|
42
|
+
export * from "./Components/Layouts/Popup.js";
|
|
43
|
+
export * from "./Components/Layouts/PopupDock.js";
|
|
44
|
+
export * from "./Components/Layouts/PopupHost.js";
|
|
45
|
+
export * from "./Components/Layouts/PopupRules.js";
|
|
46
|
+
export * from "./Components/Layouts/ThemePicker.js";
|
|
47
|
+
export * from "./Components/Layouts/ThemeSwitcher.js";
|
|
48
|
+
export * from "./Components/Layouts/Toaster.js";
|
|
49
|
+
export * from "./Components/Viewers/DataTable.js";
|
|
50
|
+
export * from "./Components/Viewers/DataTableParts.js";
|
|
51
|
+
// Helpers
|
|
52
|
+
export * from "./Helpers/ChatHooks.js";
|
|
53
|
+
export * from "./Helpers/DatePreferences.js";
|
|
54
|
+
export * from "./Helpers/DragHelpers.js";
|
|
55
|
+
export * from "./Helpers/PopoverHelpers.js";
|
|
56
|
+
// Services
|
|
57
|
+
export * from "./Services/BrowserApi.js";
|
|
58
|
+
export * from "./Services/ChatApi.js";
|
|
59
|
+
export * from "./Services/ExcelApi.js";
|
|
60
|
+
export * from "./Services/ThemeService.js";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ChatDomainValue } from "../../Interfaces/ChatInterfaces.ts";
|
|
3
|
+
import { type PopupSize } from "../Layouts/Popup.tsx";
|
|
4
|
+
import { type ChatPanelProps } from "./ChatPanel.tsx";
|
|
5
|
+
export interface ChatProps<TDomain extends ChatDomainValue = ChatDomainValue> extends Omit<ChatPanelProps<TDomain>, "scope" | "header" | "enabled" | "height"> {
|
|
6
|
+
/** Which kind of record: `EDomainTypes.Leave`. */
|
|
7
|
+
domain: TDomain;
|
|
8
|
+
/** The record's own id. */
|
|
9
|
+
parentId: string | number;
|
|
10
|
+
/** Who is reading and writing. */
|
|
11
|
+
userId: string | number;
|
|
12
|
+
/** What the icon is called, in its tooltip and for a screen reader. Default: the domain's name, else "Discussion". */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Default `md`, as the other controls in a row; `sm` for a dense table. */
|
|
15
|
+
buttonSize?: "sm" | "md";
|
|
16
|
+
/** How wide the popup is. Default `md` (560px). */
|
|
17
|
+
popupSize?: PopupSize;
|
|
18
|
+
/** How tall the conversation is inside the popup. Default `min(60vh, 520px)`. */
|
|
19
|
+
height?: number | string;
|
|
20
|
+
/** The popup's title bar. Default: the panel's `title`, else the domain's name and the record's id. */
|
|
21
|
+
popupTitle?: ReactNode;
|
|
22
|
+
/** Opened or closed. */
|
|
23
|
+
onOpenChange?: (open: boolean) => void;
|
|
24
|
+
/** Class of the trigger icon. */
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
/** The chat icon for a record, and the conversation in a popup. */
|
|
28
|
+
export declare function Chat<TDomain extends ChatDomainValue = ChatDomainValue>({ domain, parentId, userId, label, buttonSize, popupSize, height, popupTitle, onOpenChange, className, summary, title, description, ...panel }: ChatProps<TDomain>): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { iconMessageCircle, InlineIcon } from "nexus-icons";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { chatDomainLabel } from "../../Helpers/ChatBackend.js";
|
|
6
|
+
import { Popup } from "../Layouts/Popup.js";
|
|
7
|
+
import { ChatButton } from "./ChatButton.js";
|
|
8
|
+
import { ChatPanel } from "./ChatPanel.js";
|
|
9
|
+
/** The chat icon for a record, and the conversation in a popup. */
|
|
10
|
+
export function Chat({ domain, parentId, userId, label, buttonSize = "md", popupSize = "md", height, popupTitle, onOpenChange, className, summary, title, description, ...panel }) {
|
|
11
|
+
const [open, setOpen] = useState(false);
|
|
12
|
+
const scope = { domain, parentId, userId };
|
|
13
|
+
const named = title ?? (chatDomainLabel(domain) ? `${chatDomainLabel(domain)} · #${String(parentId)}` : `Discussion · #${String(parentId)}`);
|
|
14
|
+
const change = (next) => {
|
|
15
|
+
setOpen(next);
|
|
16
|
+
onOpenChange?.(next);
|
|
17
|
+
};
|
|
18
|
+
return (_jsxs(_Fragment, { children: [_jsx(ChatButton, { scope: scope, summary: summary, label: label ?? chatDomainLabel(domain) ?? "Discussion", size: buttonSize, className: className, onClick: () => change(true) }), _jsx(Popup, { open: open, onClose: () => change(false), title: popupTitle ?? named, description: description, icon: _jsx(InlineIcon, { icon: iconMessageCircle }), variant: "window", size: popupSize, reopen: "restore", flush: true, closeOnBackdrop: false, children: _jsx(ChatPanel, { ...panel, scope: scope, summary: summary, title: named, header: false, enabled: open, height: height ?? "100%" }) })] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type IconNode } from "nexus-icons";
|
|
2
|
+
import { type ComponentPropsWithRef } from "react";
|
|
3
|
+
import { type ChatTimeOptions } from "../../Helpers/ChatHelpers.ts";
|
|
4
|
+
import type { ChatDomainValue, ChatScope, ChatSummary } from "../../Interfaces/ChatInterfaces.ts";
|
|
5
|
+
export interface ChatButtonProps<TDomain extends ChatDomainValue = ChatDomainValue> extends Omit<ComponentPropsWithRef<"button">, "children" | "title" | "aria-label"> {
|
|
6
|
+
/** Which conversation: the domain, the record, and the reader. */
|
|
7
|
+
scope: ChatScope<TDomain>;
|
|
8
|
+
/** The counts, when the row already carries them. Without them the icon asks the page's cache. */
|
|
9
|
+
summary?: ChatSummary;
|
|
10
|
+
/** What the conversation is called, in the tooltip and for a screen reader. Default "Discussion". */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Default `md` (34px), as the other controls in a row. `sm` is 28px, for a dense table. */
|
|
13
|
+
size?: "sm" | "md";
|
|
14
|
+
/** The largest number the badge writes before "99+". Default 99. */
|
|
15
|
+
maxBadge?: number;
|
|
16
|
+
/** The user's date settings, for "3 h ago" in the tooltip. Default: their own. */
|
|
17
|
+
time?: ChatTimeOptions;
|
|
18
|
+
/** The icon. Default: a speech bubble. */
|
|
19
|
+
icon?: IconNode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The chat icon for one record: quiet, highlighted, or highlighted with an unread badge. It does not open anything by
|
|
23
|
+
* itself — `Chat` is the icon with the popup behind it, and a page that holds the conversation somewhere else gives
|
|
24
|
+
* this one an `onClick`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ChatButton<TDomain extends ChatDomainValue = ChatDomainValue>({ scope, summary: given, label, size, maxBadge, time, icon, className, ...rest }: ChatButtonProps<TDomain>): import("react").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { iconMessageCircle, InlineIcon } from "nexus-icons";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import { chatBadgeText, chatHighlight, chatPreviewText, chatTimeAgo } from "../../Helpers/ChatHelpers.js";
|
|
6
|
+
import { useChatSummary } from "../../Helpers/ChatHooks.js";
|
|
7
|
+
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
8
|
+
import { useBrowserTimeZone, useDatePreferences } from "../../Helpers/DatePreferences.js";
|
|
9
|
+
import { pluralize } from "../../Helpers/MessageBuilder.js";
|
|
10
|
+
/**
|
|
11
|
+
* The tooltip and the screen reader's text: what the icon is saying, in words. "40 min ago" is left out until the page
|
|
12
|
+
* is in a browser — it is counted from the clock, and a server that rendered "42 min ago" a moment earlier would not
|
|
13
|
+
* match what the browser then draws. The zone tells us where we are, as the date-time fields here already have it.
|
|
14
|
+
*/
|
|
15
|
+
function describe(summary, label, time, onBrowser) {
|
|
16
|
+
if (!summary || summary.messageCount === 0)
|
|
17
|
+
return `${label}: no messages yet`;
|
|
18
|
+
const counted = `${summary.messageCount} ${summary.messageCount === 1 ? "message" : pluralize("message")}`;
|
|
19
|
+
const parts = [summary.unreadCount > 0 ? `${label}: ${summary.unreadCount} unread of ${summary.messageCount}` : `${label}: ${counted}`];
|
|
20
|
+
const when = onBrowser ? chatTimeAgo(summary.lastMessageAt, time) : "";
|
|
21
|
+
if (when)
|
|
22
|
+
parts.push(when);
|
|
23
|
+
if (summary.lastMessageText)
|
|
24
|
+
parts.push(`${summary.lastMessageBy ? `${summary.lastMessageBy}: ` : ""}${chatPreviewText(summary.lastMessageText, 80)}`);
|
|
25
|
+
return parts.join(" · ");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The chat icon for one record: quiet, highlighted, or highlighted with an unread badge. It does not open anything by
|
|
29
|
+
* itself — `Chat` is the icon with the popup behind it, and a page that holds the conversation somewhere else gives
|
|
30
|
+
* this one an `onClick`.
|
|
31
|
+
*/
|
|
32
|
+
export function ChatButton({ scope, summary: given, label = "Discussion", size = "md", maxBadge = 99, time, icon = iconMessageCircle, className, ...rest }) {
|
|
33
|
+
const { summary } = useChatSummary(scope, given);
|
|
34
|
+
const preferences = useDatePreferences();
|
|
35
|
+
const zone = useBrowserTimeZone();
|
|
36
|
+
const settings = useMemo(() => ({ ...preferences, ...(zone && { timeZone: zone }), ...time }), [preferences, zone, time]);
|
|
37
|
+
const highlight = chatHighlight(summary);
|
|
38
|
+
const words = describe(summary, label, settings, zone !== null);
|
|
39
|
+
const unread = summary?.unreadCount ?? 0;
|
|
40
|
+
return (_jsxs("button", { type: "button", className: cx("nx-chat-btn", `nx-chat-btn--${size}`, className), "data-chat": highlight, title: words, "aria-label": words, ...rest, children: [_jsx(InlineIcon, { icon: icon }), unread > 0 && (_jsx("span", { className: "nx-chat-btn__badge", "aria-hidden": "true", children: chatBadgeText(unread, maxBadge) }))] }));
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ChatSnapshot, ChatStore } from "../../Helpers/ChatStore.ts";
|
|
2
|
+
import type { ChatMessage, ChatParticipant } from "../../Interfaces/ChatInterfaces.ts";
|
|
3
|
+
import { type MarkdownToolbarItem } from "../Inputs/MarkdownEditor.tsx";
|
|
4
|
+
/** The tools a chat message needs. The full `MARKDOWN_TOOLBAR` belongs to a document, not to a line or two. */
|
|
5
|
+
export declare const CHAT_TOOLBAR: readonly MarkdownToolbarItem[];
|
|
6
|
+
/** `enter`: Enter sends, Shift+Enter starts a line. `modifier`: Ctrl+Enter sends and Enter is only ever a line. */
|
|
7
|
+
export type ChatSendKey = "enter" | "modifier";
|
|
8
|
+
export interface ChatComposerProps {
|
|
9
|
+
store: ChatStore;
|
|
10
|
+
state: ChatSnapshot;
|
|
11
|
+
/** Keeps the unsent text under this key. Default: none, and the text is lost when the composer unmounts. */
|
|
12
|
+
draftKey?: string;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
/** Files can be attached. Default false: only a source that takes them should offer it. */
|
|
15
|
+
files?: boolean;
|
|
16
|
+
/** The message being answered. */
|
|
17
|
+
replyTo?: ChatMessage | null;
|
|
18
|
+
/** The reply was called off. */
|
|
19
|
+
onCancelReply?: () => void;
|
|
20
|
+
/** Which key sends. Default `enter`. */
|
|
21
|
+
sendKey?: ChatSendKey;
|
|
22
|
+
/**
|
|
23
|
+
* The people an `@` offers. Left out, `@` is only a letter. The list opens on `@` at the start of a word and
|
|
24
|
+
* narrows as the name is typed; Enter or Tab puts the name in, and while it is open Enter never sends.
|
|
25
|
+
*/
|
|
26
|
+
mentions?: readonly ChatParticipant[];
|
|
27
|
+
/** Where a mention links to, as Markdown: `person => `/people/${person.id}``. Default: plain `@Name`, no link. */
|
|
28
|
+
mentionHref?: (participant: ChatParticipant) => string | null;
|
|
29
|
+
/** The toolbar, as `MarkdownEditor` takes it. Default `CHAT_TOOLBAR`; `[]` leaves the writing area bare. */
|
|
30
|
+
toolbar?: readonly MarkdownToolbarItem[];
|
|
31
|
+
/** How tall the writing area starts, in pixels. Default 84, about three lines; the handle under it drags, and remembers. */
|
|
32
|
+
height?: number;
|
|
33
|
+
/** Why the user may not write here. */
|
|
34
|
+
readOnlyMessage?: string;
|
|
35
|
+
/** Most characters in one message. Default 4,000. */
|
|
36
|
+
maxLength?: number;
|
|
37
|
+
autoFocus?: boolean;
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Writes and sends a message, in Markdown. */
|
|
41
|
+
export declare function ChatComposer({ store, state, draftKey, placeholder, files, replyTo, onCancelReply, sendKey, mentions, mentionHref, toolbar, height, readOnlyMessage, maxLength, autoFocus, className, }: ChatComposerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { iconPaperclip, iconSend, iconX, InlineIcon } from "nexus-icons";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import { applyChatMention, chatFileSize, findChatMention, matchChatMentions, readChatMentions } from "../../Helpers/ChatHelpers.js";
|
|
6
|
+
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
7
|
+
import { continueMarkdownList } from "../../Helpers/MarkdownEditing.js";
|
|
8
|
+
import { markdownToPlainText } from "../../Helpers/MarkdownHelpers.js";
|
|
9
|
+
import { ChatAvatar } from "./ChatParts.js";
|
|
10
|
+
import { MarkdownEditor } from "../Inputs/MarkdownEditor.js";
|
|
11
|
+
/*
|
|
12
|
+
* The composer. A message is Markdown, so this is the Markdown editor the rest of the app writes with — the same
|
|
13
|
+
* toolbar, the same shortcuts, the same preview — kept short, with Write and Preview only and no room for a split view
|
|
14
|
+
* in a chat panel.
|
|
15
|
+
*
|
|
16
|
+
* Enter sends and Shift+Enter starts a line, as a chat does. The one exception is a list: with the caret in one, Enter
|
|
17
|
+
* belongs to the editor, which carries the list on to the next item, because a half-written list that sends itself is
|
|
18
|
+
* worse than a message that needs one more key. A page that would rather Enter never sent sets `sendKey="modifier"`.
|
|
19
|
+
*
|
|
20
|
+
* What has been typed but not sent is kept under `draftKey`, so closing the panel, opening another record, or reloading
|
|
21
|
+
* the page does not lose it — the same promise the forms make.
|
|
22
|
+
*/
|
|
23
|
+
/** Where unsent text is kept. */
|
|
24
|
+
const DRAFT_PREFIX = "nx-chat-draft:";
|
|
25
|
+
/** The tools a chat message needs. The full `MARKDOWN_TOOLBAR` belongs to a document, not to a line or two. */
|
|
26
|
+
export const CHAT_TOOLBAR = ["bold", "italic", "strikethrough", "|", "link", "code", "codeBlock", "|", "bulletList", "numberedList", "taskList", "quote"];
|
|
27
|
+
const readDraft = (key) => {
|
|
28
|
+
if (!key || typeof window === "undefined")
|
|
29
|
+
return "";
|
|
30
|
+
try {
|
|
31
|
+
return window.localStorage.getItem(DRAFT_PREFIX + key) ?? "";
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// A private window, or site data turned off: the composer simply starts empty.
|
|
35
|
+
return "";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const writeDraft = (key, text) => {
|
|
39
|
+
if (!key || typeof window === "undefined")
|
|
40
|
+
return;
|
|
41
|
+
try {
|
|
42
|
+
if (text)
|
|
43
|
+
window.localStorage.setItem(DRAFT_PREFIX + key, text);
|
|
44
|
+
else
|
|
45
|
+
window.localStorage.removeItem(DRAFT_PREFIX + key);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Nothing to do: losing a draft is better than failing to send.
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/** Whether the caret sits inside a fenced code block, where Enter is a line and never a send. */
|
|
52
|
+
function insideCodeFence(value, caret) {
|
|
53
|
+
const before = value.slice(0, caret);
|
|
54
|
+
return (before.match(/^```/gm) ?? []).length % 2 === 1;
|
|
55
|
+
}
|
|
56
|
+
/** Writes and sends a message, in Markdown. */
|
|
57
|
+
export function ChatComposer({ store, state, draftKey, placeholder = "Write a message…", files = false, replyTo, onCancelReply, sendKey = "enter", mentions, mentionHref, toolbar = CHAT_TOOLBAR, height = 84, readOnlyMessage = "You can read this conversation, but not write in it.", maxLength = 4000, autoFocus = false, className, }) {
|
|
58
|
+
const boxRef = useRef(null);
|
|
59
|
+
const fileRef = useRef(null);
|
|
60
|
+
// The text lives here so Send, the draft, and clearing after a send all read the same thing. A message is short, so
|
|
61
|
+
// a render per keystroke costs nothing — unlike the long documents the editor is otherwise built for.
|
|
62
|
+
//
|
|
63
|
+
// It starts empty rather than from the saved draft: local storage is the browser's, so reading it while rendering
|
|
64
|
+
// would make the page the server built and the page the browser builds disagree, down to a Send button that is
|
|
65
|
+
// disabled on one and not the other. The draft arrives just after, in the effect below.
|
|
66
|
+
const [text, setText] = useState("");
|
|
67
|
+
const [picked, setPicked] = useState([]);
|
|
68
|
+
// The `@…` being typed, and which of the people offered is highlighted.
|
|
69
|
+
const [mention, setMention] = useState(null);
|
|
70
|
+
const [at, setAt] = useState(0);
|
|
71
|
+
const offered = mention && mentions ? matchChatMentions(mentions, mention.query) : [];
|
|
72
|
+
const picking = offered.length > 0;
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
setText(readDraft(draftKey));
|
|
75
|
+
}, [draftKey]);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (autoFocus)
|
|
78
|
+
boxRef.current?.focus();
|
|
79
|
+
}, [autoFocus]);
|
|
80
|
+
const change = useCallback((value) => {
|
|
81
|
+
setText(value);
|
|
82
|
+
writeDraft(draftKey, value);
|
|
83
|
+
// The caret is the text area's, since the editor hands back only the text.
|
|
84
|
+
const caret = boxRef.current?.selectionStart ?? value.length;
|
|
85
|
+
setMention(mentions ? findChatMention(value, caret) : null);
|
|
86
|
+
setAt(0);
|
|
87
|
+
}, [draftKey, mentions]);
|
|
88
|
+
/** Puts the chosen name in, and leaves the caret after it. */
|
|
89
|
+
const putMention = useCallback((person) => {
|
|
90
|
+
if (!mention)
|
|
91
|
+
return;
|
|
92
|
+
const next = applyChatMention(text, mention, person, mentionHref?.(person));
|
|
93
|
+
setText(next.value);
|
|
94
|
+
writeDraft(draftKey, next.value);
|
|
95
|
+
setMention(null);
|
|
96
|
+
const box = boxRef.current;
|
|
97
|
+
if (box) {
|
|
98
|
+
// After the editor has drawn the new text, or the caret would be put back by the render.
|
|
99
|
+
requestAnimationFrame(() => {
|
|
100
|
+
box.focus();
|
|
101
|
+
box.setSelectionRange(next.caret, next.caret);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}, [mention, text, mentionHref, draftKey]);
|
|
105
|
+
const send = useCallback(() => {
|
|
106
|
+
const written = text.trim();
|
|
107
|
+
if (!written && picked.length === 0)
|
|
108
|
+
return;
|
|
109
|
+
// The text goes before the call does: the message is on screen at once, and a failure keeps it there with Retry.
|
|
110
|
+
const named = mentions ? readChatMentions(written, mentions) : [];
|
|
111
|
+
change("");
|
|
112
|
+
setPicked([]);
|
|
113
|
+
setMention(null);
|
|
114
|
+
onCancelReply?.();
|
|
115
|
+
void store.send(written, { replyToId: replyTo?.id ?? null, ...(picked.length > 0 && { files: picked }), ...(named.length > 0 && { mentions: named }) });
|
|
116
|
+
boxRef.current?.focus();
|
|
117
|
+
}, [text, picked, change, onCancelReply, store, replyTo, mentions]);
|
|
118
|
+
const keyDown = (event) => {
|
|
119
|
+
// While the `@` list is open it owns the arrows, Enter, Tab and Esc: a name is being picked, not a message sent.
|
|
120
|
+
if (picking) {
|
|
121
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
setAt(index => (index + (event.key === "ArrowDown" ? 1 : offered.length - 1)) % offered.length);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (event.key === "Enter" || event.key === "Tab") {
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
putMention(offered[at] ?? offered[0]);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (event.key === "Escape") {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
setMention(null);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// While an input method is composing, Enter belongs to the composition, not to sending.
|
|
138
|
+
if (event.key !== "Enter" || event.nativeEvent.isComposing) {
|
|
139
|
+
if (event.key === "Escape" && replyTo && onCancelReply) {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
onCancelReply();
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const withModifier = event.ctrlKey || event.metaKey;
|
|
146
|
+
if (sendKey === "modifier") {
|
|
147
|
+
if (!withModifier)
|
|
148
|
+
return;
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
send();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (event.shiftKey || event.altKey)
|
|
154
|
+
return;
|
|
155
|
+
const box = event.currentTarget;
|
|
156
|
+
// The editor owns Enter inside a list or a code block: it carries the list on, or keeps the block together.
|
|
157
|
+
if (!withModifier && (continueMarkdownList(box.value, box.selectionStart, box.selectionEnd) !== null || insideCodeFence(box.value, box.selectionStart)))
|
|
158
|
+
return;
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
send();
|
|
161
|
+
};
|
|
162
|
+
const addFiles = (event) => {
|
|
163
|
+
const chosen = Array.from(event.target.files ?? []);
|
|
164
|
+
if (chosen.length)
|
|
165
|
+
setPicked(held => [...held, ...chosen]);
|
|
166
|
+
event.target.value = "";
|
|
167
|
+
};
|
|
168
|
+
if (!state.canSend) {
|
|
169
|
+
return (_jsx("div", { className: cx("nx-chat-composer nx-chat-composer--readonly", className), children: _jsx("p", { children: readOnlyMessage }) }));
|
|
170
|
+
}
|
|
171
|
+
const empty = text.trim() === "" && picked.length === 0;
|
|
172
|
+
return (_jsxs("div", { className: cx("nx-chat-composer", className), children: [replyTo && (_jsxs("div", { className: "nx-chat-composer__reply", children: [_jsxs("span", { className: "nx-chat-composer__reply-text", children: [_jsx("span", { className: "nx-chat-composer__reply-author", children: replyTo.authorName || "Unknown" }), _jsx("span", { children: markdownToPlainText(replyTo.body) })] }), _jsx("button", { type: "button", onClick: onCancelReply, "aria-label": "Stop replying", children: _jsx(InlineIcon, { icon: iconX }) })] })), picked.length > 0 && (_jsx("ul", { className: "nx-chat-composer__files", children: picked.map((file, index) => (_jsxs("li", { children: [_jsx("span", { className: "nx-chat-composer__file-name", children: file.name }), _jsx("span", { className: "nx-chat-composer__file-size", children: chatFileSize(file.size) }), _jsx("button", { type: "button", onClick: () => setPicked(held => held.filter((_, at) => at !== index)), "aria-label": `Remove ${file.name}`, children: _jsx(InlineIcon, { icon: iconX }) })] }, `${file.name}-${index}`))) })), picking && (_jsx("ul", { className: "nx-chat-mentions", role: "listbox", "aria-label": "People", children: offered.map((person, index) => (_jsx("li", { children: _jsxs("button", { type: "button", className: cx("nx-chat-mentions__item", index === at && "is-at"), role: "option", "aria-selected": index === at,
|
|
173
|
+
// The editor must not lose the caret before the name goes in.
|
|
174
|
+
onMouseDown: event => event.preventDefault(), onMouseEnter: () => setAt(index), onClick: () => putMention(person), children: [_jsx(ChatAvatar, { name: person.name, src: person.avatar, size: "sm" }), _jsx("span", { className: "nx-chat-mentions__name", children: person.name }), person.role && _jsx("span", { className: "nx-chat-mentions__role", children: person.role })] }) }, String(person.id)))) })), _jsx(MarkdownEditor, { ref: boxRef, className: "nx-chat-composer__editor", "aria-label": "Message", placeholder: placeholder, value: text, onValueChange: change, onKeyDown: keyDown,
|
|
175
|
+
// Moving the caret away from an `@…` closes the list, as clicking elsewhere in the text does.
|
|
176
|
+
onSelect: () => setMention(mentions ? findChatMention(boxRef.current?.value ?? "", boxRef.current?.selectionStart ?? 0) : null), onBlur: () => setMention(null), modes: ["write", "preview"], toolbar: toolbar, height: height, minHeight: 72, maxHeight: 360, heightKey: "nx-chat", showCount: false, maxLength: maxLength }), _jsxs("div", { className: "nx-chat-composer__row", children: [_jsx("span", { className: "nx-chat-composer__hint", children: sendKey === "enter" ? "Enter sends · Shift+Enter for a line" : "Ctrl+Enter sends" }), files && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "nx-chat-composer__attach", onClick: () => fileRef.current?.click(), "aria-label": "Attach a file", title: "Attach a file", children: _jsx(InlineIcon, { icon: iconPaperclip }) }), _jsx("input", { ref: fileRef, type: "file", multiple: true, hidden: true, onChange: addFiles })] })), _jsxs("button", { type: "button", className: "nx-chat-composer__send", onClick: send, disabled: empty, "aria-label": "Send", title: sendKey === "enter" ? "Send (Enter)" : "Send (Ctrl+Enter)", children: [_jsx(InlineIcon, { icon: iconSend }), _jsx("span", { children: "Send" })] })] })] }));
|
|
177
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type ChatTimeOptions } from "../../Helpers/ChatHelpers.ts";
|
|
3
|
+
import type { ChatPlaceHandle } from "../../Helpers/ChatHooks.ts";
|
|
4
|
+
import type { ChatConversation, ChatId } from "../../Interfaces/ChatInterfaces.ts";
|
|
5
|
+
export interface ChatConversationListProps {
|
|
6
|
+
conversations: readonly ChatConversation[];
|
|
7
|
+
/** The one open now. */
|
|
8
|
+
currentId?: ChatId | null;
|
|
9
|
+
userId: ChatId;
|
|
10
|
+
time: ChatTimeOptions;
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
error?: string | null;
|
|
13
|
+
onRetry?: () => void;
|
|
14
|
+
onPick: (conversation: ChatConversation) => void;
|
|
15
|
+
/** Starts a new one. Left out when the source cannot. */
|
|
16
|
+
onNew?: () => void;
|
|
17
|
+
/** Shown when the record holds none. */
|
|
18
|
+
empty?: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/** Every conversation at a record: which is open, which is waiting, and what was said last. */
|
|
21
|
+
export declare function ChatConversationList({ conversations, currentId, userId, time, loading, error, onRetry, onPick, onNew, empty }: ChatConversationListProps): import("react").JSX.Element;
|
|
22
|
+
export interface ChatNewFormProps {
|
|
23
|
+
place: ChatPlaceHandle;
|
|
24
|
+
/** Searches people. Default: the place's own search. */
|
|
25
|
+
searchParticipants?: ChatPlaceHandle["searchParticipants"];
|
|
26
|
+
/** The conversation that was started, or the one that already existed. */
|
|
27
|
+
onStarted: (conversation: ChatConversation) => void;
|
|
28
|
+
onCancel: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Starts a conversation. The **type is not asked for**: one person makes a one-to-one, more than one makes a group,
|
|
32
|
+
* and naming it makes a group of one person too. The form says which it will be, so nothing is a surprise, and the
|
|
33
|
+
* backend has the last word — asking a one-to-one for somebody who already has one gives that one back.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ChatNewForm({ place, searchParticipants, onStarted, onCancel }: ChatNewFormProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { iconMessageCircle, iconPlus, iconUsers, InlineIcon } from "nexus-icons";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { chatBadgeText, chatConversationName, chatPreviewText, chatTimeAgo, chatTypeFor } from "../../Helpers/ChatHelpers.js";
|
|
6
|
+
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
7
|
+
import { Button } from "../Documents/Button.js";
|
|
8
|
+
import { Dropdown } from "../Inputs/Dropdown.js";
|
|
9
|
+
import { TextBox } from "../Inputs/TextBox.js";
|
|
10
|
+
import { ChatAvatar, ChatFailure, ChatLoading } from "./ChatParts.js";
|
|
11
|
+
/** Every conversation at a record: which is open, which is waiting, and what was said last. */
|
|
12
|
+
export function ChatConversationList({ conversations, currentId, userId, time, loading, error, onRetry, onPick, onNew, empty }) {
|
|
13
|
+
return (_jsxs("div", { className: "nx-chat-list", children: [error && _jsx(ChatFailure, { message: error, onRetry: onRetry }), loading && conversations.length === 0 && _jsx(ChatLoading, { label: "Reading the conversations\u2026" }), !loading && conversations.length === 0 && !error && (_jsxs("div", { className: "nx-chat-empty", children: [_jsx("p", { children: empty ?? "No conversations here yet." }), onNew && _jsx("p", { className: "nx-chat-empty__hint", children: "Start one below." })] })), conversations.length > 0 && (_jsx("ul", { className: "nx-chat-list__items", children: conversations.map(conversation => {
|
|
14
|
+
const name = chatConversationName(conversation, userId);
|
|
15
|
+
const unread = conversation.summary?.unreadCount ?? 0;
|
|
16
|
+
const when = chatTimeAgo(conversation.summary?.lastMessageAt, time);
|
|
17
|
+
const last = conversation.summary?.lastMessageText;
|
|
18
|
+
const current = currentId !== null && currentId !== undefined && String(conversation.id) === String(currentId);
|
|
19
|
+
return (_jsx("li", { children: _jsxs("button", { type: "button", className: cx("nx-chat-list__item", current && "is-current"), onClick: () => onPick(conversation), "aria-current": current || undefined, children: [conversation.type === "group" ? (_jsx("span", { className: "nx-chat-list__group", "aria-hidden": "true", children: _jsx(InlineIcon, { icon: iconUsers }) })) : (_jsx(ChatAvatar, { name: name, src: (conversation.participants ?? []).find(person => String(person.id) !== String(userId))?.avatar })), _jsxs("span", { className: "nx-chat-list__text", children: [_jsxs("span", { className: "nx-chat-list__line", children: [_jsx("span", { className: "nx-chat-list__name", children: name }), when && _jsx("span", { className: "nx-chat-list__when", children: when })] }), _jsxs("span", { className: "nx-chat-list__line", children: [_jsx("span", { className: "nx-chat-list__last", children: last ? `${conversation.summary?.lastMessageBy ? `${conversation.summary.lastMessageBy}: ` : ""}${chatPreviewText(last, 60)}` : "No messages yet" }), unread > 0 && _jsx("span", { className: "nx-chat-list__badge", children: chatBadgeText(unread) })] })] })] }) }, String(conversation.id)));
|
|
20
|
+
}) })), onNew && (_jsx("div", { className: "nx-chat-list__new", children: _jsx(Button, { size: "sm", variant: "secondary", block: true, icon: _jsx(InlineIcon, { icon: iconPlus }), onClick: onNew, children: "New chat" }) }))] }));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Starts a conversation. The **type is not asked for**: one person makes a one-to-one, more than one makes a group,
|
|
24
|
+
* and naming it makes a group of one person too. The form says which it will be, so nothing is a surprise, and the
|
|
25
|
+
* backend has the last word — asking a one-to-one for somebody who already has one gives that one back.
|
|
26
|
+
*/
|
|
27
|
+
export function ChatNewForm({ place, searchParticipants, onStarted, onCancel }) {
|
|
28
|
+
const [chosen, setChosen] = useState([]);
|
|
29
|
+
const [title, setTitle] = useState("");
|
|
30
|
+
const search = searchParticipants ?? place.searchParticipants;
|
|
31
|
+
const type = chatTypeFor(chosen, title);
|
|
32
|
+
async function start() {
|
|
33
|
+
const made = await place.create({ type, userIds: chosen, title: title.trim() || null });
|
|
34
|
+
if (made)
|
|
35
|
+
onStarted(made);
|
|
36
|
+
}
|
|
37
|
+
return (_jsxs("div", { className: "nx-chat-new", children: [_jsxs("div", { className: "nx-chat-new__fields", children: [_jsx(Dropdown, { multiple: true, name: "nx-chat-new-people", label: "With", placeholder: "Search by name", size: "sm", value: chosen, valueKey: "id", labelKey: "name", descriptionKey: "role", loadOptions: search, isOptionInactive: (person) => person.inactive === true, onValueChange: (values) => setChosen(values), hint: chosen.length === 0 ? "One person makes a direct chat; more make a group." : undefined }), (chosen.length > 1 || title !== "") && (_jsx(TextBox, { name: "nx-chat-new-title", label: "Group name", size: "sm", value: title, onValueChange: setTitle, maxLength: 120, placeholder: "Optional", hint: "Without one, the group is called after the people in it." })), _jsxs("p", { className: "nx-chat-new__kind", children: [_jsx(InlineIcon, { icon: type === "group" ? iconUsers : iconMessageCircle }), chosen.length === 0 ? "Pick who to talk to." : type === "group" ? `A group of ${chosen.length + 1}, you included.` : "A direct chat between the two of you."] }), place.error && _jsx(ChatFailure, { message: place.error })] }), _jsxs("div", { className: "nx-chat-new__actions", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: onCancel, children: "Cancel" }), _jsx(Button, { size: "sm", variant: "primary", loading: place.creating, disabled: chosen.length === 0, onClick: () => void start(), children: "Start chat" })] }), _jsx("p", { className: "nx-chat-new__note", children: "You are in it either way." })] }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ChatConversation, ChatDomainValue, ChatId, ChatParticipant, ChatParticipantPage, ChatParticipantQuery, ChatPlaceSource, ChatScope, ChatSource, ChatSummary } from "../../Interfaces/ChatInterfaces.ts";
|
|
3
|
+
/** Which of the panel's three views the body is showing. */
|
|
4
|
+
export type ChatPanelView = "thread" | "list" | "new";
|
|
5
|
+
export interface ChatPanelProps<TDomain extends ChatDomainValue = ChatDomainValue> {
|
|
6
|
+
/** Which record: the domain, the record, and the reader. */
|
|
7
|
+
scope: ChatScope<TDomain>;
|
|
8
|
+
/**
|
|
9
|
+
* Where the messages of **one** conversation come from. Given, the panel shows that conversation alone, with no
|
|
10
|
+
* switch and no New chat. Left out, the panel asks the place which conversations the record holds.
|
|
11
|
+
*/
|
|
12
|
+
source?: ChatSource;
|
|
13
|
+
/**
|
|
14
|
+
* Where one conversation's messages come from, when the app carries them itself — a socket for each conversation, or
|
|
15
|
+
* a demo with them in memory. Called with whichever conversation is open. Default: the app's API, by conversation id.
|
|
16
|
+
*/
|
|
17
|
+
sourceFor?: (conversation: ChatConversation) => ChatSource | undefined;
|
|
18
|
+
/** The conversations at this record, and how to start another. Default: the app's API, through its `ChatBackend`. */
|
|
19
|
+
place?: ChatPlaceSource;
|
|
20
|
+
/** The conversations the page already had, so the panel makes no call for them. */
|
|
21
|
+
conversations?: readonly ChatConversation[];
|
|
22
|
+
/** Which conversation to open. Default: the one with unread messages, else the one spoken in most recently. */
|
|
23
|
+
conversationId?: ChatId | null;
|
|
24
|
+
/** When another conversation is opened, so a page can remember which. */
|
|
25
|
+
onConversationChange?: (conversation: ChatConversation | null) => void;
|
|
26
|
+
/** What the record is: "Leave request #482". Default: the domain's name and the record's id. */
|
|
27
|
+
title?: ReactNode;
|
|
28
|
+
/** A line under the title, such as who asked and when. */
|
|
29
|
+
description?: ReactNode;
|
|
30
|
+
/** The counts the page already had, so the bar opens filled. */
|
|
31
|
+
summary?: ChatSummary;
|
|
32
|
+
/** The people the page already had, so the panel makes no call for them. */
|
|
33
|
+
participants?: readonly ChatParticipant[];
|
|
34
|
+
/**
|
|
35
|
+
* Searches the people in the conversation and the ones who could join. Default: the source's own search (the
|
|
36
|
+
* backend's participants endpoint). Give one to search somewhere else — a staff list, a project's members.
|
|
37
|
+
*/
|
|
38
|
+
searchParticipants?: (query: ChatParticipantQuery) => Promise<ChatParticipantPage>;
|
|
39
|
+
/** The people column and its button. Default true when anyone is known or can be searched. */
|
|
40
|
+
people?: boolean;
|
|
41
|
+
/** Files can be attached. Default false. */
|
|
42
|
+
files?: boolean;
|
|
43
|
+
/** Messages can be answered. Default true. */
|
|
44
|
+
replies?: boolean;
|
|
45
|
+
/** `@` offers the people in the conversation. Default true. */
|
|
46
|
+
mentions?: boolean;
|
|
47
|
+
/** Where a mention links to, as Markdown: `person => \`/people/${person.id}\``. Default: plain `@Name`, no link. */
|
|
48
|
+
mentionHref?: (participant: ChatParticipant) => string | null;
|
|
49
|
+
/** The bar above the thread. Off inside a popup, whose own title bar says what this is. Default true. */
|
|
50
|
+
header?: boolean;
|
|
51
|
+
/** How tall the panel is. Default `min(60vh, 520px)`; `"100%"` fills what holds it. */
|
|
52
|
+
height?: number | string;
|
|
53
|
+
/** Loads and watches only while this is true. Default true. */
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
/** Messages per page. Default 30. */
|
|
56
|
+
pageSize?: number;
|
|
57
|
+
/** Milliseconds between checks for new messages. 0 turns it off. Default 15,000. */
|
|
58
|
+
pollInterval?: number;
|
|
59
|
+
/** Every time the record's counts change, so a list's row can follow them. */
|
|
60
|
+
onSummary?: (summary: ChatSummary) => void;
|
|
61
|
+
/** Buttons under the composer. */
|
|
62
|
+
footer?: ReactNode;
|
|
63
|
+
className?: string;
|
|
64
|
+
}
|
|
65
|
+
/** A record's conversations, drawn in full. */
|
|
66
|
+
export declare function ChatPanel<TDomain extends ChatDomainValue = ChatDomainValue>({ scope, source, sourceFor, place: placeSource, conversations: givenConversations, conversationId: givenConversationId, onConversationChange, title, description, summary, participants, searchParticipants, people, files, replies, mentions, mentionHref, header, height, enabled, pageSize, pollInterval, onSummary, footer, className, }: ChatPanelProps<TDomain>): import("react").JSX.Element;
|