nexus-shared 4.0.0 → 4.1.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 +795 -0
- package/README.md +220 -14
- package/dist/Client.Index.d.ts +13 -0
- package/dist/Client.Index.js +13 -0
- package/dist/Components/Chats/ChatComposer.d.ts +7 -1
- package/dist/Components/Chats/ChatComposer.js +9 -6
- package/dist/Components/Chats/ChatParts.d.ts +15 -2
- package/dist/Components/Chats/ChatParts.js +15 -4
- package/dist/Components/Chats/ChatPopup.d.ts +46 -0
- package/dist/Components/Chats/ChatPopup.js +34 -0
- package/dist/Components/Chats/ChatThread.d.ts +9 -1
- package/dist/Components/Chats/ChatThread.js +54 -6
- package/dist/Components/Dashboards/DashboardBoard.d.ts +62 -0
- package/dist/Components/Dashboards/DashboardBoard.js +594 -0
- package/dist/Components/Dashboards/DashboardWidgets.d.ts +155 -0
- package/dist/Components/Dashboards/DashboardWidgets.js +159 -0
- package/dist/Components/Dashboards/WidgetFrame.d.ts +51 -0
- package/dist/Components/Dashboards/WidgetFrame.js +45 -0
- package/dist/Components/Documents/Button.d.ts +6 -1
- package/dist/Components/Documents/Button.js +2 -2
- package/dist/Components/Documents/TabButtons.d.ts +6 -0
- package/dist/Components/Documents/TabButtons.js +5 -4
- package/dist/Components/Domains/DomainCard.d.ts +98 -0
- package/dist/Components/Domains/DomainCard.js +182 -0
- package/dist/Components/Forms/ApiForm.js +5 -1
- package/dist/Components/Forms/Crud.js +72 -24
- package/dist/Components/Forms/CrudActions.d.ts +5 -4
- package/dist/Components/Forms/CrudActions.js +42 -12
- package/dist/Components/Forms/CrudHistory.d.ts +6 -1
- package/dist/Components/Forms/CrudHistory.js +14 -6
- package/dist/Components/Forms/CrudParts.d.ts +11 -4
- package/dist/Components/Forms/CrudParts.js +76 -10
- package/dist/Components/Forms/CrudRowForms.js +65 -5
- package/dist/Components/Forms/CrudTree.js +7 -7
- package/dist/Components/Forms/CrudWorkspace.d.ts +15 -5
- package/dist/Components/Forms/CrudWorkspace.js +19 -11
- package/dist/Components/Forms/Form.d.ts +3 -2
- package/dist/Components/Forms/Form.js +33 -26
- package/dist/Components/Forms/FormQuestion.d.ts +6 -0
- package/dist/Components/Forms/FormQuestion.js +28 -0
- package/dist/Components/Forms/SubmitForm.js +2 -15
- package/dist/Components/Inputs/ComputedInput.d.ts +51 -0
- package/dist/Components/Inputs/ComputedInput.js +179 -0
- package/dist/Components/Inputs/Dropdown.js +4 -2
- package/dist/Components/Inputs/GroupForm.js +3 -2
- package/dist/Components/Inputs/InputRenderer.d.ts +5 -1
- package/dist/Components/Inputs/MarkdownEditor.d.ts +6 -0
- package/dist/Components/Inputs/MarkdownEditor.js +32 -6
- package/dist/Components/Inputs/PictureInput.js +8 -3
- package/dist/Components/Inputs/RowsInput.d.ts +14 -1
- package/dist/Components/Inputs/RowsInput.js +78 -5
- package/dist/Components/Inputs/TabularForm.js +16 -3
- package/dist/Components/Inputs/TreeView.d.ts +24 -1
- package/dist/Components/Inputs/TreeView.js +84 -7
- package/dist/Components/Layouts/Popup.d.ts +22 -2
- package/dist/Components/Layouts/Popup.js +108 -6
- package/dist/Components/Messages/MailClient.d.ts +50 -0
- package/dist/Components/Messages/MailClient.js +410 -0
- package/dist/Components/Messages/MailColumns.d.ts +21 -0
- package/dist/Components/Messages/MailColumns.js +92 -0
- package/dist/Components/Messages/MailCompose.d.ts +46 -0
- package/dist/Components/Messages/MailCompose.js +154 -0
- package/dist/Components/Messages/MailReader.d.ts +43 -0
- package/dist/Components/Messages/MailReader.js +207 -0
- package/dist/Components/Messages/MailThread.d.ts +71 -0
- package/dist/Components/Messages/MailThread.js +185 -0
- package/dist/Components/Messages/MessageBell.d.ts +41 -0
- package/dist/Components/Messages/MessageBell.js +76 -0
- package/dist/Components/Viewers/DataTable.js +7 -5
- package/dist/Components/Viewers/DataTableColumns.d.ts +2 -2
- package/dist/Components/Viewers/DataTableColumns.js +2 -1
- package/dist/Components/Viewers/DataTableParts.d.ts +3 -1
- package/dist/Components/Viewers/DataTableParts.js +2 -2
- package/dist/Components/Viewers/OwnerFiles.d.ts +57 -5
- package/dist/Components/Viewers/OwnerFiles.js +142 -31
- package/dist/Helpers/ApiModules.js +4 -0
- package/dist/Helpers/AuditEntries.d.ts +50 -0
- package/dist/Helpers/AuditEntries.js +96 -0
- package/dist/Helpers/ChatBackend.d.ts +8 -1
- package/dist/Helpers/ChatBackend.js +18 -0
- package/dist/Helpers/ChatHelpers.d.ts +2 -0
- package/dist/Helpers/ChatHelpers.js +4 -1
- package/dist/Helpers/CrudColumns.d.ts +44 -6
- package/dist/Helpers/CrudColumns.js +63 -13
- package/dist/Helpers/CrudHelpers.d.ts +36 -1
- package/dist/Helpers/CrudHelpers.js +61 -0
- package/dist/Helpers/CrudPickerPlan.d.ts +58 -0
- package/dist/Helpers/CrudPickerPlan.js +46 -0
- package/dist/Helpers/CrudRowForms.d.ts +18 -1
- package/dist/Helpers/CrudRowForms.js +35 -2
- package/dist/Helpers/DashboardHelpers.d.ts +115 -0
- package/dist/Helpers/DashboardHelpers.js +305 -0
- package/dist/Helpers/DomainCards.d.ts +140 -0
- package/dist/Helpers/DomainCards.js +370 -0
- package/dist/Helpers/FileAdapter.d.ts +82 -2
- package/dist/Helpers/FileAdapter.js +72 -1
- package/dist/Helpers/FormStore.d.ts +11 -1
- package/dist/Helpers/FormStore.js +66 -19
- package/dist/Helpers/InputConditions.d.ts +6 -0
- package/dist/Helpers/InputConditions.js +24 -0
- package/dist/Helpers/InputMemory.js +40 -30
- package/dist/Helpers/InputNarrowing.d.ts +38 -6
- package/dist/Helpers/InputNarrowing.js +102 -21
- package/dist/Helpers/MailClientHelpers.d.ts +96 -0
- package/dist/Helpers/MailClientHelpers.js +211 -0
- package/dist/Helpers/MessageBackend.d.ts +152 -0
- package/dist/Helpers/MessageBackend.js +329 -0
- package/dist/Helpers/MessageHelpers.d.ts +160 -0
- package/dist/Helpers/MessageHelpers.js +573 -0
- package/dist/Helpers/MessageUnread.d.ts +95 -0
- package/dist/Helpers/MessageUnread.js +245 -0
- package/dist/Helpers/NexusDriveAdapter.d.ts +17 -1
- package/dist/Helpers/NexusDriveAdapter.js +32 -3
- package/dist/Helpers/NumberHelpers.d.ts +61 -0
- package/dist/Helpers/NumberHelpers.js +124 -8
- package/dist/Helpers/PagedPicker.d.ts +42 -0
- package/dist/Helpers/PagedPicker.js +85 -0
- package/dist/Helpers/RowsStore.d.ts +24 -0
- package/dist/Helpers/RowsStore.js +79 -10
- package/dist/Helpers/TableHelpers.d.ts +15 -2
- package/dist/Helpers/TableHelpers.js +28 -1
- package/dist/Helpers/TableStore.d.ts +7 -3
- package/dist/Helpers/TableStore.js +9 -4
- package/dist/Helpers/ToolbarFit.d.ts +23 -0
- package/dist/Helpers/ToolbarFit.js +30 -0
- package/dist/Helpers/TreeStore.d.ts +75 -6
- package/dist/Helpers/TreeStore.js +182 -18
- package/dist/Interfaces/ApiInterfaces.d.ts +10 -1
- package/dist/Interfaces/ApiInterfaces.js +10 -1
- package/dist/Interfaces/ChatInterfaces.d.ts +22 -0
- package/dist/Interfaces/CrudInterfaces.d.ts +78 -5
- package/dist/Interfaces/DashboardInterfaces.d.ts +123 -0
- package/dist/Interfaces/DashboardInterfaces.js +1 -0
- package/dist/Interfaces/DomainInterfaces.d.ts +145 -0
- package/dist/Interfaces/DomainInterfaces.js +1 -0
- package/dist/Interfaces/FileInterfaces.d.ts +21 -0
- package/dist/Interfaces/FileInterfaces.js +2 -0
- package/dist/Interfaces/FormInterfaces.d.ts +78 -11
- package/dist/Interfaces/InputInterfaces.d.ts +12 -5
- package/dist/Interfaces/MailInterfaces.d.ts +192 -0
- package/dist/Interfaces/MailInterfaces.js +1 -0
- package/dist/Interfaces/TableInterfaces.d.ts +28 -2
- package/dist/Services/JoinSources.d.ts +47 -6
- package/dist/Services/JoinSources.js +68 -33
- package/dist/Services/MessageApi.d.ts +18 -0
- package/dist/Services/MessageApi.js +64 -0
- package/dist/Shared.Index.d.ts +12 -0
- package/dist/Shared.Index.js +12 -0
- package/package.json +7 -1
- package/src/Styles/Nexus.Button.css +29 -0
- package/src/Styles/Nexus.Chat.css +114 -22
- package/src/Styles/Nexus.Crud.css +119 -28
- package/src/Styles/Nexus.Dashboard.css +763 -0
- package/src/Styles/Nexus.Domain.css +384 -0
- package/src/Styles/Nexus.Editor.css +20 -0
- package/src/Styles/Nexus.Files.css +27 -0
- package/src/Styles/Nexus.Index.css +3 -0
- package/src/Styles/Nexus.Input.css +31 -0
- package/src/Styles/Nexus.Mail.css +1062 -0
- package/src/Styles/Nexus.Popup.css +58 -0
- package/src/Styles/Nexus.Table.css +1458 -1449
- package/src/Styles/Nexus.Theme.Picker.css +1 -0
- package/src/Styles/Nexus.Tree.css +10 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { iconMinus, iconSquare, iconSquares, iconX, InlineIcon } from "nexus-icons";
|
|
4
4
|
import { useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
5
|
-
import { flushSync } from "react-dom";
|
|
5
|
+
import { createPortal, flushSync } from "react-dom";
|
|
6
6
|
import { afterAnimation, motionAllowed } from "../../Helpers/AnimationHelpers.js";
|
|
7
7
|
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
8
8
|
import { cssVariablePosition, DRAG_CANCEL_SELECTOR, moveWithin, startDrag, viewportBounds } from "../../Helpers/DragHelpers.js";
|
|
@@ -12,6 +12,57 @@ const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([t
|
|
|
12
12
|
// Where a minimized popup flies to: the newest bar of the dock, at the bottom right.
|
|
13
13
|
const DOCK_EDGE = 16;
|
|
14
14
|
const DOCK_BAR = { width: 300, height: 44 };
|
|
15
|
+
// Docked windows (`docked`), in the order they opened (each next one to the left of the one before), and in the order
|
|
16
|
+
// they were last used (the last on top).
|
|
17
|
+
const DOCKED_GAP = 12;
|
|
18
|
+
let dockedOrder = [];
|
|
19
|
+
let dockedStack = [];
|
|
20
|
+
let dockedObserver = null;
|
|
21
|
+
/** Lays the open docked windows out along the bottom edge, and stacks them by use. */
|
|
22
|
+
function layoutDocked() {
|
|
23
|
+
const view = document.documentElement.clientWidth;
|
|
24
|
+
let right = DOCK_EDGE;
|
|
25
|
+
for (const dialog of dockedOrder) {
|
|
26
|
+
if (!dialog.open)
|
|
27
|
+
continue;
|
|
28
|
+
const width = dialog.offsetWidth;
|
|
29
|
+
// A window with no room left of the others stands at the right again, over them: the last used shows on top.
|
|
30
|
+
const fits = right + width + DOCK_EDGE <= view;
|
|
31
|
+
dialog.style.setProperty("--nx-docked-right", `${fits ? right : DOCK_EDGE}px`);
|
|
32
|
+
if (fits)
|
|
33
|
+
right += width + DOCKED_GAP;
|
|
34
|
+
}
|
|
35
|
+
dockedStack.forEach((dialog, index) => dialog.style.setProperty("--nx-docked-z", String(index + 1)));
|
|
36
|
+
}
|
|
37
|
+
function dockedJoin(dialog) {
|
|
38
|
+
if (!dockedOrder.includes(dialog))
|
|
39
|
+
dockedOrder = [...dockedOrder, dialog];
|
|
40
|
+
dockedRaise(dialog);
|
|
41
|
+
if (!dockedObserver) {
|
|
42
|
+
dockedObserver = new ResizeObserver(layoutDocked);
|
|
43
|
+
window.addEventListener("resize", layoutDocked);
|
|
44
|
+
}
|
|
45
|
+
dockedObserver.observe(dialog);
|
|
46
|
+
layoutDocked();
|
|
47
|
+
}
|
|
48
|
+
function dockedLeave(dialog) {
|
|
49
|
+
dockedOrder = dockedOrder.filter(one => one !== dialog);
|
|
50
|
+
dockedStack = dockedStack.filter(one => one !== dialog);
|
|
51
|
+
dockedObserver?.unobserve(dialog);
|
|
52
|
+
if (dockedOrder.length === 0 && dockedObserver) {
|
|
53
|
+
dockedObserver.disconnect();
|
|
54
|
+
dockedObserver = null;
|
|
55
|
+
window.removeEventListener("resize", layoutDocked);
|
|
56
|
+
}
|
|
57
|
+
layoutDocked();
|
|
58
|
+
}
|
|
59
|
+
/** The docked window last used comes on top of the others. */
|
|
60
|
+
function dockedRaise(dialog) {
|
|
61
|
+
if (dockedStack[dockedStack.length - 1] === dialog)
|
|
62
|
+
return;
|
|
63
|
+
dockedStack = [...dockedStack.filter(one => one !== dialog), dialog];
|
|
64
|
+
layoutDocked();
|
|
65
|
+
}
|
|
15
66
|
function popupPosition(dialog) {
|
|
16
67
|
return cssVariablePosition(dialog, "--nx-popup-x", "--nx-popup-y");
|
|
17
68
|
}
|
|
@@ -30,7 +81,10 @@ const homes = new WeakMap();
|
|
|
30
81
|
* @example
|
|
31
82
|
* <Popup open={open} onClose={() => setOpen(false)} title="Edit booking" footer={<Button variant="primary">Save</Button>}>…</Popup>
|
|
32
83
|
*/
|
|
33
|
-
export function Popup({ open, onClose, onClosed, title, description, icon, variant = "window", size = "md", footer, closable = true, closeOnEscape = true, closeOnBackdrop = true, minimizable, maximizable = true, movable = true, reopen = "replace", windowState: windowStateProp, defaultWindowState = "normal", onWindowStateChange, flush = false, initialFocus, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, className, children, }) {
|
|
84
|
+
export function Popup({ open, onClose, onClosed, title, description, icon, variant = "window", size = "md", height, footer, closable = true, closeOnEscape = true, closeOnBackdrop = true, minimizable, maximizable: maximizableProp = true, movable: movableProp = true, reopen = "replace", docked = false, drawer = false, windowState: windowStateProp, defaultWindowState = "normal", onWindowStateChange, flush = false, initialFocus, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, className, children, }) {
|
|
85
|
+
// A drawer stands at its edge: it neither moves nor maximizes.
|
|
86
|
+
const maximizable = maximizableProp && !drawer;
|
|
87
|
+
const movable = movableProp && !drawer;
|
|
34
88
|
const id = useId();
|
|
35
89
|
const dialogRef = useRef(null);
|
|
36
90
|
// Content stays mounted through the exit animation, and while minimized.
|
|
@@ -61,6 +115,13 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
61
115
|
// The box before a maximize or a restore, for the animation between the two.
|
|
62
116
|
const flipFromRef = useRef(null);
|
|
63
117
|
const dockId = `nx-window${id}`;
|
|
118
|
+
// A docked window is drawn on the page's body, never inside what opened it: a scroller, a container or a transform
|
|
119
|
+
// there would carry it along or cut it off. Only once the page is in the browser, where a window can be opened.
|
|
120
|
+
const [portalReady, setPortalReady] = useState(false);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (docked)
|
|
123
|
+
setPortalReady(true);
|
|
124
|
+
}, [docked]);
|
|
64
125
|
function changeWindowState(next) {
|
|
65
126
|
if (next === latest.current.windowState)
|
|
66
127
|
return;
|
|
@@ -120,8 +181,12 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
120
181
|
if (top)
|
|
121
182
|
(homes.get(top) ?? (() => top.focus()))();
|
|
122
183
|
}
|
|
184
|
+
// Where the focus starts: the asked-for element; else what the content marked as its start (`data-nx-focus`, such as a
|
|
185
|
+
// mail thread's subject, so a long read opens at its top and not on its first link or scroller); else the first control.
|
|
123
186
|
function focusInside(dialog) {
|
|
124
|
-
const target = initialFocus
|
|
187
|
+
const target = initialFocus
|
|
188
|
+
? dialog.querySelector(initialFocus)
|
|
189
|
+
: (dialog.querySelector(":is(.nx-popup__body, .nx-popup__foot) [data-nx-focus]") ?? dialog.querySelector(`:is(.nx-popup__body, .nx-popup__foot) :is(${FOCUSABLE})`));
|
|
125
190
|
(target ?? dialog).focus();
|
|
126
191
|
}
|
|
127
192
|
useLayoutEffect(() => {
|
|
@@ -130,6 +195,12 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
130
195
|
homes.set(dialog, () => focusInside(dialog));
|
|
131
196
|
});
|
|
132
197
|
function showDialog(dialog) {
|
|
198
|
+
// A docked window leaves the page as it is: no backdrop, no lock, laid out beside the others.
|
|
199
|
+
if (docked) {
|
|
200
|
+
dialog.show();
|
|
201
|
+
dockedJoin(dialog);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
133
204
|
// The first modal locks the page; the space of its scrollbar is kept as padding, so nothing shifts.
|
|
134
205
|
if (!document.querySelector(".nx-popup:modal"))
|
|
135
206
|
document.documentElement.style.setProperty("--nx-scrollbar-gap", `${window.innerWidth - document.documentElement.clientWidth}px`);
|
|
@@ -138,6 +209,8 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
138
209
|
function closeDialog(dialog) {
|
|
139
210
|
selfCloseRef.current = true;
|
|
140
211
|
dialog.close();
|
|
212
|
+
if (docked)
|
|
213
|
+
layoutDocked();
|
|
141
214
|
returnFocus();
|
|
142
215
|
}
|
|
143
216
|
// After the popup has closed: the content unmounts, and the next opening starts centered, in its default state.
|
|
@@ -234,7 +307,7 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
234
307
|
focusInside(dialog);
|
|
235
308
|
}
|
|
236
309
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
237
|
-
}, [open, minimized]);
|
|
310
|
+
}, [open, minimized, portalReady]);
|
|
238
311
|
// Closing: the exit animation plays, then the dialog closes and the content unmounts. Without the animation
|
|
239
312
|
// (reduced motion), it closes in the same frame.
|
|
240
313
|
useLayoutEffect(() => {
|
|
@@ -319,6 +392,28 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
319
392
|
useEffect(() => () => undock(),
|
|
320
393
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
321
394
|
[]);
|
|
395
|
+
// A docked window leaves the row of docked windows when it goes.
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
const dialog = dialogRef.current;
|
|
398
|
+
if (!docked || !dialog)
|
|
399
|
+
return;
|
|
400
|
+
return () => dockedLeave(dialog);
|
|
401
|
+
}, [docked, portalReady]);
|
|
402
|
+
// Esc inside a docked window closes it: the browser asks only a modal one. A menu or a list inside that took the key
|
|
403
|
+
// first keeps it.
|
|
404
|
+
function onKeyDown(event) {
|
|
405
|
+
if (!docked || event.key !== "Escape" || event.defaultPrevented || closing)
|
|
406
|
+
return;
|
|
407
|
+
event.preventDefault();
|
|
408
|
+
if (closeOnEscape)
|
|
409
|
+
onClose("escape");
|
|
410
|
+
}
|
|
411
|
+
// The docked window used last comes on top.
|
|
412
|
+
function raise() {
|
|
413
|
+
const dialog = dialogRef.current;
|
|
414
|
+
if (docked && dialog)
|
|
415
|
+
dockedRaise(dialog);
|
|
416
|
+
}
|
|
322
417
|
// Esc: the browser asks to close; the page decides through onClose.
|
|
323
418
|
function onCancel(event) {
|
|
324
419
|
event.preventDefault();
|
|
@@ -348,7 +443,8 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
348
443
|
function onClick(event) {
|
|
349
444
|
const onBackdrop = event.target === event.currentTarget && downOnBackdropRef.current;
|
|
350
445
|
downOnBackdropRef.current = false;
|
|
351
|
-
|
|
446
|
+
// A docked window has no backdrop: a press on its own edge is not outside it.
|
|
447
|
+
if (onBackdrop && closeOnBackdrop && !closing && !docked)
|
|
352
448
|
onClose("backdrop");
|
|
353
449
|
}
|
|
354
450
|
// A mouse click on minimize or maximize leaves focus in the field being typed in, as a desktop window's buttons do.
|
|
@@ -397,5 +493,11 @@ export function Popup({ open, onClose, onClosed, title, description, icon, varia
|
|
|
397
493
|
const titleId = `${id}-title`;
|
|
398
494
|
const descriptionId = `${id}-description`;
|
|
399
495
|
const hasControls = canMinimize || maximizable || closable;
|
|
400
|
-
|
|
496
|
+
const element = (_jsx("dialog", { ref: dialogRef, className: cx("nx-popup", `nx-popup--${variant}`, `nx-popup--${size}`, docked && "nx-popup--docked", drawer && "nx-popup--drawer", flush && "nx-popup--flush", maximized && "nx-popup--maximized", movable && "nx-popup--movable", closing && "nx-popup--closing", className), "data-window-state": windowState, style: height === undefined ? undefined : { "--nx-popup-height": typeof height === "number" ? `${height}px` : height }, "aria-labelledby": title ? titleId : undefined, "aria-label": title ? undefined : ariaLabel, "aria-describedby": cx(description ? descriptionId : undefined, ariaDescribedBy) || undefined, onCancel: onCancel, onClose: onNativeClose, onPointerDown: event => {
|
|
497
|
+
raise();
|
|
498
|
+
onPointerDown(event);
|
|
499
|
+
}, onFocus: raise, onKeyDown: onKeyDown, onMouseDown: onMouseDown, onClick: onClick, children: shown && (_jsxs(HostedPopupContext, { value: false, children: [(title || icon || hasControls) && (_jsxs("header", { className: "nx-popup__head", onPointerDown: onHeadPointerDown, onDoubleClick: onHeadDoubleClick, children: [icon && _jsx("span", { className: "nx-popup__icon", children: icon }), _jsxs("div", { className: "nx-popup__heading", children: [title && (_jsx("h2", { id: titleId, className: "nx-popup__title", children: title })), description && (_jsx("p", { id: descriptionId, className: "nx-popup__description", children: description }))] }), hasControls && (_jsxs("div", { className: "nx-popup__controls", children: [canMinimize && (_jsx("button", { type: "button", className: "nx-popup__control nx-popup__minimize", "aria-label": "Minimize", title: "Minimize", onMouseDown: keepFocus, onClick: () => changeWindowState("minimized"), children: _jsx(InlineIcon, { icon: iconMinus }) })), maximizable && (_jsx("button", { type: "button", className: "nx-popup__control nx-popup__maximize", "aria-label": maximized ? "Restore down" : "Maximize", title: maximized ? "Restore down" : "Maximize", onMouseDown: keepFocus, onClick: toggleMaximize, children: _jsx(InlineIcon, { icon: maximized ? iconSquares : iconSquare }) })), closable && (_jsx("button", { type: "button", className: "nx-popup__control nx-popup__close", "aria-label": "Close", title: "Close", onClick: () => onClose("close"), children: _jsx(InlineIcon, { icon: iconX }) }))] }))] })), _jsx("div", { className: "nx-popup__body", children: children }), footer && _jsx("footer", { className: "nx-popup__foot", children: footer })] }, round)) }));
|
|
500
|
+
if (!docked)
|
|
501
|
+
return element;
|
|
502
|
+
return portalReady ? createPortal(element, document.body) : null;
|
|
401
503
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type MailClientView } from "../../Helpers/MailClientHelpers.ts";
|
|
3
|
+
import type { ChatId, ChatSource } from "../../Interfaces/ChatInterfaces.ts";
|
|
4
|
+
import type { MailDomain, MailInboxRow, MessageSource } from "../../Interfaces/MailInterfaces.ts";
|
|
5
|
+
import type { MailDomainContext } from "./MailThread.tsx";
|
|
6
|
+
export interface MailClientProps {
|
|
7
|
+
/** Where the mailbox's data comes from: one object for the page (the bell polls on it too). */
|
|
8
|
+
source: MessageSource;
|
|
9
|
+
/** Who is reading. */
|
|
10
|
+
userId: ChatId;
|
|
11
|
+
/**
|
|
12
|
+
* The bar's heading. Default "Message". `false` draws none, for a page whose own heading names the client (an admin
|
|
13
|
+
* page's title from its menu row): the search then starts the bar, and the page has one heading.
|
|
14
|
+
*/
|
|
15
|
+
title?: ReactNode | false;
|
|
16
|
+
/** A sentence beside the title, clipped to the rail's width, the whole of it on hover: what a page's own heading would say. */
|
|
17
|
+
description?: ReactNode;
|
|
18
|
+
/** The title's heading level: 1 when the client takes the page's own title. Default 2. */
|
|
19
|
+
headingLevel?: 1 | 2 | 3;
|
|
20
|
+
/** The folder and type shown, when the page controls them (a URL); pair with `onViewChange`. */
|
|
21
|
+
view?: MailClientView;
|
|
22
|
+
/** The folder and type shown first, when the page does not control them. Default the Inbox, every type. */
|
|
23
|
+
defaultView?: MailClientView;
|
|
24
|
+
onViewChange?: (view: MailClientView) => void;
|
|
25
|
+
/**
|
|
26
|
+
* The conversation open in the pane, when the page controls it (`?thread=`); pair with `onThreadChange`. A chat named
|
|
27
|
+
* here (the bell's link, an e-mail copy's) opens its chat window too, as a click on its row does.
|
|
28
|
+
*/
|
|
29
|
+
threadId?: ChatId | null;
|
|
30
|
+
onThreadChange?: (threadId: ChatId | null) => void;
|
|
31
|
+
/** At the end of the bar: the app's settings, a gear `Button` that links to its admin pages. */
|
|
32
|
+
settings?: ReactNode;
|
|
33
|
+
/** Conversations per page of the list. Default 50. */
|
|
34
|
+
pageSize?: number;
|
|
35
|
+
/** A chat's lines, when they do not come from the source's `threadSource`. */
|
|
36
|
+
chatSourceFor?: (row: MailInboxRow) => ChatSource;
|
|
37
|
+
/** Draws the record a mail is about. Default its `DomainCard`. */
|
|
38
|
+
renderDomain?: (domain: MailDomain, context: MailDomainContext) => ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* After anything that changes what is unread or where a conversation is - a read mark once the server answered it, a
|
|
41
|
+
* mark, an archive: a page's bell reads again (`refreshMessageUnread`). The client's own counts wait for every read
|
|
42
|
+
* mark on its way, so a page needs no wrapper of its own around the source for them.
|
|
43
|
+
*/
|
|
44
|
+
onChanged?: () => void;
|
|
45
|
+
/** Milliseconds between quiet reads of the list and its counts while the page is in front. 0 turns it off. Default 60,000. */
|
|
46
|
+
pollInterval?: number;
|
|
47
|
+
className?: string;
|
|
48
|
+
}
|
|
49
|
+
/** A mailbox as a mail client: rail, list and reading pane, with chat popups and compose windows docked at the bottom right. */
|
|
50
|
+
export declare function MailClient({ source, userId, title, description, headingLevel, view: viewProp, defaultView, onViewChange, threadId: threadProp, onThreadChange, settings, pageSize, chatSourceFor, renderDomain, onChanged, pollInterval, className, }: MailClientProps): import("react").JSX.Element;
|