@natoe/colab 0.1.11 → 0.1.13
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/dist/index.d.mts +140 -14
- package/dist/index.d.ts +140 -14
- package/dist/index.js +1086 -616
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1085 -618
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,39 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Channel } from 'phoenix';
|
|
4
4
|
|
|
5
|
+
/** CSS variable names for the themeable color tokens. */
|
|
6
|
+
declare const THEME_VAR: {
|
|
7
|
+
readonly primary: "--natoe-colab-primary";
|
|
8
|
+
readonly primaryHover: "--natoe-colab-primary-hover";
|
|
9
|
+
readonly primaryBg: "--natoe-colab-primary-bg";
|
|
10
|
+
readonly primaryFg: "--natoe-colab-primary-fg";
|
|
11
|
+
readonly success: "--natoe-colab-success";
|
|
12
|
+
readonly warning: "--natoe-colab-warning";
|
|
13
|
+
readonly danger: "--natoe-colab-danger";
|
|
14
|
+
readonly dangerBg: "--natoe-colab-danger-bg";
|
|
15
|
+
readonly dangerBorder: "--natoe-colab-danger-border";
|
|
16
|
+
readonly dangerFg: "--natoe-colab-danger-fg";
|
|
17
|
+
readonly fontStack: "--natoe-colab-font-stack";
|
|
18
|
+
};
|
|
19
|
+
/** Default values for the themeable tokens (used by both CSS emission and
|
|
20
|
+
* the inline-style fallback inside `var(..., fallback)`). */
|
|
21
|
+
declare const THEME_DEFAULTS: {
|
|
22
|
+
readonly primary: "#2563eb";
|
|
23
|
+
readonly primaryHover: "#1d4ed8";
|
|
24
|
+
readonly primaryBg: "#dbeafe";
|
|
25
|
+
readonly primaryFg: "#1d4ed8";
|
|
26
|
+
readonly success: "#059669";
|
|
27
|
+
readonly warning: "#d97706";
|
|
28
|
+
readonly danger: "#dc2626";
|
|
29
|
+
readonly dangerBg: "#fef2f2";
|
|
30
|
+
readonly dangerBorder: "#fecaca";
|
|
31
|
+
readonly dangerFg: "#b91c1c";
|
|
32
|
+
readonly fontStack: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif";
|
|
33
|
+
};
|
|
34
|
+
/** Public override shape — passed via CollabConfig.theme. Every key is
|
|
35
|
+
* optional; unspecified keys fall back to {@link THEME_DEFAULTS}. */
|
|
36
|
+
type Theme = Partial<Record<keyof typeof THEME_DEFAULTS, string>>;
|
|
37
|
+
|
|
5
38
|
interface CollabConfig {
|
|
6
39
|
/** Phoenix WebSocket URL (e.g. wss://backend.natoe.ai/socket) */
|
|
7
40
|
socketUrl: string;
|
|
@@ -12,6 +45,15 @@ interface CollabConfig {
|
|
|
12
45
|
userRole: UserRole;
|
|
13
46
|
userName: string;
|
|
14
47
|
userAvatar?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Optional theme overrides. Any key set here is applied as a CSS custom
|
|
50
|
+
* property on `:root`, replacing the package's default for that token.
|
|
51
|
+
* Keys not provided keep their default. See {@link Theme} for the
|
|
52
|
+
* complete list of overridable tokens (brand + semantic colors + font
|
|
53
|
+
* stack). Spacing, type scale, radii are deliberately not themeable —
|
|
54
|
+
* changing those wholesale breaks the package's visual rhythm.
|
|
55
|
+
*/
|
|
56
|
+
theme?: Theme;
|
|
15
57
|
/** Host app callbacks — colab calls these, never implements them */
|
|
16
58
|
onOpenDicom?: (studyId: string, storageId: string) => void;
|
|
17
59
|
onUploadFile?: (file: File | Blob, fileName?: string) => Promise<string>;
|
|
@@ -23,6 +65,8 @@ interface PatientData {
|
|
|
23
65
|
patientName: string;
|
|
24
66
|
patientAge?: string;
|
|
25
67
|
patientSex?: string;
|
|
68
|
+
/** Patient MRN — shown on inbox rows and searchable in the inbox filter. */
|
|
69
|
+
patientId?: string;
|
|
26
70
|
studyType?: string;
|
|
27
71
|
studyId?: string;
|
|
28
72
|
storageId?: string;
|
|
@@ -145,8 +189,13 @@ interface SendMessagePayload {
|
|
|
145
189
|
media_duration?: number;
|
|
146
190
|
file_name?: string;
|
|
147
191
|
metadata?: Record<string, unknown>;
|
|
148
|
-
/**
|
|
149
|
-
|
|
192
|
+
/**
|
|
193
|
+
* ID of message being replied to (snapshot is built server-side).
|
|
194
|
+
* Wire-level key is snake_case to match the channel handler — the
|
|
195
|
+
* other optional fields here (media_url, file_name, …) follow the
|
|
196
|
+
* same convention.
|
|
197
|
+
*/
|
|
198
|
+
reply_to_id?: string;
|
|
150
199
|
}
|
|
151
200
|
type ChannelEvent = 'message:new' | 'message:read' | 'message:pinned' | 'message:unpinned' | 'user:typing' | 'user:joined' | 'user:left' | 'channel:updated' | 'channel:deleted';
|
|
152
201
|
interface TypingEvent {
|
|
@@ -185,6 +234,13 @@ interface CollabPanelProps {
|
|
|
185
234
|
onBack?: () => void;
|
|
186
235
|
/** Hide the patient name row in the header — set when a parent already shows it (e.g. CollabPopup title bar) */
|
|
187
236
|
hidePatientName?: boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Notified whenever the underlying conversation state changes (initial
|
|
239
|
+
* preview load, create, channel deletion). Lets a parent like CollabPopup
|
|
240
|
+
* render its title bar from the authoritative conversation.name instead of
|
|
241
|
+
* relying on potentially-incomplete patientData.
|
|
242
|
+
*/
|
|
243
|
+
onConversationChange?: (conversation: Conversation | null) => void;
|
|
188
244
|
/** Custom class name for the outer container */
|
|
189
245
|
className?: string;
|
|
190
246
|
/** Custom inline styles for the outer container */
|
|
@@ -194,7 +250,7 @@ interface CollabPanelProps {
|
|
|
194
250
|
* Full collaboration panel: patient header + pinned bar + message thread + input.
|
|
195
251
|
* Supports reply, pin/unpin, and (optionally) seen-by indicators.
|
|
196
252
|
*/
|
|
197
|
-
declare function CollabPanel({ orderId, patientData, participantIds, showSeenBy, onBack, hidePatientName, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
253
|
+
declare function CollabPanel({ orderId, patientData, participantIds, showSeenBy, onBack, hidePatientName, onConversationChange, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
198
254
|
|
|
199
255
|
interface CollabPopupProps {
|
|
200
256
|
/** Order ID for this conversation */
|
|
@@ -209,6 +265,14 @@ interface CollabPopupProps {
|
|
|
209
265
|
onClose: () => void;
|
|
210
266
|
/** Optional back navigation — renders a ← button in the title bar when provided */
|
|
211
267
|
onBack?: () => void;
|
|
268
|
+
/**
|
|
269
|
+
* When provided, the minimize button calls this callback instead of
|
|
270
|
+
* toggling the popup's own shrink-to-titlebar state. Hosts use this
|
|
271
|
+
* to minimize the popup to an external chip / dock. With this set the
|
|
272
|
+
* minimize button always shows the minimize glyph (no expand state),
|
|
273
|
+
* since the host owns the open/minimized lifecycle.
|
|
274
|
+
*/
|
|
275
|
+
onMinimize?: () => void;
|
|
212
276
|
/** Initial position (defaults to bottom-right) */
|
|
213
277
|
initialPosition?: {
|
|
214
278
|
x: number;
|
|
@@ -224,7 +288,7 @@ interface CollabPopupProps {
|
|
|
224
288
|
* Draggable floating chat popup — drop-in replacement for DraggableChatPopup.
|
|
225
289
|
* Renders a CollabPanel inside a movable, resizable container.
|
|
226
290
|
*/
|
|
227
|
-
declare function CollabPopup({ orderId, patientData, participantIds, isOpen, onClose, onBack, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
291
|
+
declare function CollabPopup({ orderId, patientData, participantIds, isOpen, onClose, onBack, onMinimize, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
228
292
|
|
|
229
293
|
interface CollabInlineProps {
|
|
230
294
|
orderId: string;
|
|
@@ -257,8 +321,6 @@ interface CollabInboxProps {
|
|
|
257
321
|
initialConversationId?: string;
|
|
258
322
|
/** Optional callback when the user selects a conversation */
|
|
259
323
|
onSelectConversation?: (item: ConversationListItem$1) => void;
|
|
260
|
-
/** Title for the sidebar */
|
|
261
|
-
title?: string;
|
|
262
324
|
className?: string;
|
|
263
325
|
style?: React.CSSProperties;
|
|
264
326
|
}
|
|
@@ -269,7 +331,7 @@ interface CollabInboxProps {
|
|
|
269
331
|
* Uses the same CollabPanel as the floating popup, so all features
|
|
270
332
|
* (reply, pin, seen-by, DICOM, voice, attachments) are available.
|
|
271
333
|
*/
|
|
272
|
-
declare function CollabInbox({ initialConversationId, onSelectConversation,
|
|
334
|
+
declare function CollabInbox({ initialConversationId, onSelectConversation, className, style, }: CollabInboxProps): react_jsx_runtime.JSX.Element;
|
|
273
335
|
|
|
274
336
|
type MessageCallback = (message: Message) => void;
|
|
275
337
|
type TypingCallback = (event: TypingEvent) => void;
|
|
@@ -365,6 +427,13 @@ interface CollabContextValue {
|
|
|
365
427
|
config: CollabConfig;
|
|
366
428
|
apiBaseUrl: string;
|
|
367
429
|
totalUnread: number;
|
|
430
|
+
/**
|
|
431
|
+
* Per-conversation unread counts, keyed by conversation ID. Updated
|
|
432
|
+
* live via the user_notifications channel's unread_update push, so
|
|
433
|
+
* surfaces like a minimized-chat chip can reflect changes without
|
|
434
|
+
* mounting their own useConversation.
|
|
435
|
+
*/
|
|
436
|
+
unreadCounts: Record<string, number>;
|
|
368
437
|
/** Batched preview lookup — coalesces calls within a microtask */
|
|
369
438
|
requestPreview: (orderId: string) => Promise<ConversationPreview | null>;
|
|
370
439
|
/** Invalidate a cached preview (e.g. when a new message arrives) */
|
|
@@ -642,14 +711,16 @@ interface ConversationListProps {
|
|
|
642
711
|
isLoading: boolean;
|
|
643
712
|
error: string | null;
|
|
644
713
|
onSelect: (item: ConversationListItem$1) => void;
|
|
645
|
-
/** Optional title shown above the list */
|
|
646
|
-
title?: string;
|
|
647
714
|
className?: string;
|
|
648
715
|
}
|
|
649
716
|
/**
|
|
650
|
-
* Scrollable
|
|
717
|
+
* Scrollable inbox of conversations. Unread/All tabs (with count pills)
|
|
718
|
+
* sit at the top, followed by a search field with a focus-within ring.
|
|
719
|
+
* On first data load with any unread items the inbox auto-defaults to
|
|
720
|
+
* the Unread tab so triage starts on what matters. Empty/loading/error
|
|
721
|
+
* states are illustrated and descriptive rather than terse one-liners.
|
|
651
722
|
*/
|
|
652
|
-
declare function ConversationList({ conversations, selectedId, isLoading, error, onSelect,
|
|
723
|
+
declare function ConversationList({ conversations, selectedId, isLoading, error, onSelect, className, }: ConversationListProps): react_jsx_runtime.JSX.Element;
|
|
653
724
|
|
|
654
725
|
interface ConversationListItemProps {
|
|
655
726
|
item: ConversationListItem$1;
|
|
@@ -658,8 +729,21 @@ interface ConversationListItemProps {
|
|
|
658
729
|
className?: string;
|
|
659
730
|
}
|
|
660
731
|
/**
|
|
661
|
-
* Single row in the inbox sidebar
|
|
662
|
-
*
|
|
732
|
+
* Single row in the inbox sidebar.
|
|
733
|
+
*
|
|
734
|
+
* Three-row layout (top-to-bottom):
|
|
735
|
+
* 1. Patient/channel name + relative time
|
|
736
|
+
* 2. Study type + monospace `MRN <patientId>` (surfaced from the
|
|
737
|
+
* snapshot; either field is optional and the row collapses if both
|
|
738
|
+
* are missing)
|
|
739
|
+
* 3. Last message preview (sender prefix in stronger weight) + unread
|
|
740
|
+
* count badge on the right
|
|
741
|
+
*
|
|
742
|
+
* Active row gets a 4px brand-color left-border accent + tinted background.
|
|
743
|
+
* The avatar is a 52px **square** tile (16px rounded corners) with brand-
|
|
744
|
+
* coloured fill and white initials — easier to scan than a circle at this
|
|
745
|
+
* size and consistent across the inbox without depending on any case
|
|
746
|
+
* status field we don't model.
|
|
663
747
|
*/
|
|
664
748
|
declare function ConversationListItem({ item, isSelected, onClick, className, }: ConversationListItemProps): react_jsx_runtime.JSX.Element;
|
|
665
749
|
|
|
@@ -676,6 +760,20 @@ interface PatientHeaderProps {
|
|
|
676
760
|
displayName?: string;
|
|
677
761
|
className?: string;
|
|
678
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* "Case card" header that sits below the window title bar. Tinted blue-50
|
|
765
|
+
* background to set it apart from the conversation body. Renders a row
|
|
766
|
+
* of labelled key-value columns (label uppercase on top, value below) for
|
|
767
|
+
* the clinical context the host passed in, with the action buttons
|
|
768
|
+
* (View DICOM + Settings) right-aligned.
|
|
769
|
+
*
|
|
770
|
+
* Used in two layouts:
|
|
771
|
+
* - Popup path (`hideName=true`): the surrounding title bar already
|
|
772
|
+
* shows the patient name, so we render the case card only.
|
|
773
|
+
* - Compact-inbox path (`hideName=false`): the panel is a full-page
|
|
774
|
+
* experience and there's no outer title, so we still show the name +
|
|
775
|
+
* back button stacked above the case card.
|
|
776
|
+
*/
|
|
679
777
|
declare function PatientHeader({ patientData, onOpenDicom, onOpenSettings, onBack, hideName, displayName, className, }: PatientHeaderProps): react_jsx_runtime.JSX.Element;
|
|
680
778
|
|
|
681
779
|
interface MessageListHandle {
|
|
@@ -857,6 +955,34 @@ interface ParticipantsListProps {
|
|
|
857
955
|
}
|
|
858
956
|
declare function ParticipantsList({ participants, currentUserId, isAdmin, onRemoveUser, className, }: ParticipantsListProps): react_jsx_runtime.JSX.Element;
|
|
859
957
|
|
|
958
|
+
/**
|
|
959
|
+
* Shared style tokens + the global stylesheet the package injects once per
|
|
960
|
+
* page.
|
|
961
|
+
*
|
|
962
|
+
* Top-level wrappers (CollabPopup, CollabPanel, CollabInline, CollabInbox)
|
|
963
|
+
* import {@link FONT_STACK} so every surface renders with the same font
|
|
964
|
+
* stack, even when the package is mounted inside an iframe whose
|
|
965
|
+
* surrounding document doesn't set one.
|
|
966
|
+
*
|
|
967
|
+
* Themeable tokens (brand + semantic colors + the font stack) are emitted
|
|
968
|
+
* as CSS custom properties on `:root` so host apps can override them via
|
|
969
|
+
* `CollabConfig.theme` (see {@link applyThemeOverrides}). Non-themeable
|
|
970
|
+
* tokens (neutrals, slate, spacing, radius, sizes) live as inline values
|
|
971
|
+
* in core/theme.ts and stay constant.
|
|
972
|
+
*
|
|
973
|
+
* The prefers-contrast / prefers-reduced-motion adjustments are emitted
|
|
974
|
+
* inside the same stylesheet so they apply wherever a `natoe-colab-root`
|
|
975
|
+
* wrapper is mounted.
|
|
976
|
+
*/
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Apply a host-supplied theme by setting CSS custom properties on the
|
|
980
|
+
* document root. Keys missing from `theme` have their previously-set
|
|
981
|
+
* override cleared so toggling overrides back to undefined returns the
|
|
982
|
+
* default — never leaves stale values behind.
|
|
983
|
+
*/
|
|
984
|
+
declare function applyThemeOverrides(theme: Theme | undefined): void;
|
|
985
|
+
|
|
860
986
|
/** Phoenix channel event names — must match backend channel implementation */
|
|
861
987
|
declare const EVENTS: {
|
|
862
988
|
readonly MESSAGE_NEW: "message:new";
|
|
@@ -895,4 +1021,4 @@ declare const SUPPORTED_IMAGE_TYPES: string[];
|
|
|
895
1021
|
/** Max file size in bytes (20MB) */
|
|
896
1022
|
declare const MAX_FILE_SIZE: number;
|
|
897
1023
|
|
|
898
|
-
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, TYPING_DEBOUNCE_MS, type TypingEvent, type UserRole, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|
|
1024
|
+
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, THEME_DEFAULTS, THEME_VAR, TYPING_DEBOUNCE_MS, type Theme, type TypingEvent, type UserRole, applyThemeOverrides, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,39 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Channel } from 'phoenix';
|
|
4
4
|
|
|
5
|
+
/** CSS variable names for the themeable color tokens. */
|
|
6
|
+
declare const THEME_VAR: {
|
|
7
|
+
readonly primary: "--natoe-colab-primary";
|
|
8
|
+
readonly primaryHover: "--natoe-colab-primary-hover";
|
|
9
|
+
readonly primaryBg: "--natoe-colab-primary-bg";
|
|
10
|
+
readonly primaryFg: "--natoe-colab-primary-fg";
|
|
11
|
+
readonly success: "--natoe-colab-success";
|
|
12
|
+
readonly warning: "--natoe-colab-warning";
|
|
13
|
+
readonly danger: "--natoe-colab-danger";
|
|
14
|
+
readonly dangerBg: "--natoe-colab-danger-bg";
|
|
15
|
+
readonly dangerBorder: "--natoe-colab-danger-border";
|
|
16
|
+
readonly dangerFg: "--natoe-colab-danger-fg";
|
|
17
|
+
readonly fontStack: "--natoe-colab-font-stack";
|
|
18
|
+
};
|
|
19
|
+
/** Default values for the themeable tokens (used by both CSS emission and
|
|
20
|
+
* the inline-style fallback inside `var(..., fallback)`). */
|
|
21
|
+
declare const THEME_DEFAULTS: {
|
|
22
|
+
readonly primary: "#2563eb";
|
|
23
|
+
readonly primaryHover: "#1d4ed8";
|
|
24
|
+
readonly primaryBg: "#dbeafe";
|
|
25
|
+
readonly primaryFg: "#1d4ed8";
|
|
26
|
+
readonly success: "#059669";
|
|
27
|
+
readonly warning: "#d97706";
|
|
28
|
+
readonly danger: "#dc2626";
|
|
29
|
+
readonly dangerBg: "#fef2f2";
|
|
30
|
+
readonly dangerBorder: "#fecaca";
|
|
31
|
+
readonly dangerFg: "#b91c1c";
|
|
32
|
+
readonly fontStack: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif";
|
|
33
|
+
};
|
|
34
|
+
/** Public override shape — passed via CollabConfig.theme. Every key is
|
|
35
|
+
* optional; unspecified keys fall back to {@link THEME_DEFAULTS}. */
|
|
36
|
+
type Theme = Partial<Record<keyof typeof THEME_DEFAULTS, string>>;
|
|
37
|
+
|
|
5
38
|
interface CollabConfig {
|
|
6
39
|
/** Phoenix WebSocket URL (e.g. wss://backend.natoe.ai/socket) */
|
|
7
40
|
socketUrl: string;
|
|
@@ -12,6 +45,15 @@ interface CollabConfig {
|
|
|
12
45
|
userRole: UserRole;
|
|
13
46
|
userName: string;
|
|
14
47
|
userAvatar?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Optional theme overrides. Any key set here is applied as a CSS custom
|
|
50
|
+
* property on `:root`, replacing the package's default for that token.
|
|
51
|
+
* Keys not provided keep their default. See {@link Theme} for the
|
|
52
|
+
* complete list of overridable tokens (brand + semantic colors + font
|
|
53
|
+
* stack). Spacing, type scale, radii are deliberately not themeable —
|
|
54
|
+
* changing those wholesale breaks the package's visual rhythm.
|
|
55
|
+
*/
|
|
56
|
+
theme?: Theme;
|
|
15
57
|
/** Host app callbacks — colab calls these, never implements them */
|
|
16
58
|
onOpenDicom?: (studyId: string, storageId: string) => void;
|
|
17
59
|
onUploadFile?: (file: File | Blob, fileName?: string) => Promise<string>;
|
|
@@ -23,6 +65,8 @@ interface PatientData {
|
|
|
23
65
|
patientName: string;
|
|
24
66
|
patientAge?: string;
|
|
25
67
|
patientSex?: string;
|
|
68
|
+
/** Patient MRN — shown on inbox rows and searchable in the inbox filter. */
|
|
69
|
+
patientId?: string;
|
|
26
70
|
studyType?: string;
|
|
27
71
|
studyId?: string;
|
|
28
72
|
storageId?: string;
|
|
@@ -145,8 +189,13 @@ interface SendMessagePayload {
|
|
|
145
189
|
media_duration?: number;
|
|
146
190
|
file_name?: string;
|
|
147
191
|
metadata?: Record<string, unknown>;
|
|
148
|
-
/**
|
|
149
|
-
|
|
192
|
+
/**
|
|
193
|
+
* ID of message being replied to (snapshot is built server-side).
|
|
194
|
+
* Wire-level key is snake_case to match the channel handler — the
|
|
195
|
+
* other optional fields here (media_url, file_name, …) follow the
|
|
196
|
+
* same convention.
|
|
197
|
+
*/
|
|
198
|
+
reply_to_id?: string;
|
|
150
199
|
}
|
|
151
200
|
type ChannelEvent = 'message:new' | 'message:read' | 'message:pinned' | 'message:unpinned' | 'user:typing' | 'user:joined' | 'user:left' | 'channel:updated' | 'channel:deleted';
|
|
152
201
|
interface TypingEvent {
|
|
@@ -185,6 +234,13 @@ interface CollabPanelProps {
|
|
|
185
234
|
onBack?: () => void;
|
|
186
235
|
/** Hide the patient name row in the header — set when a parent already shows it (e.g. CollabPopup title bar) */
|
|
187
236
|
hidePatientName?: boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Notified whenever the underlying conversation state changes (initial
|
|
239
|
+
* preview load, create, channel deletion). Lets a parent like CollabPopup
|
|
240
|
+
* render its title bar from the authoritative conversation.name instead of
|
|
241
|
+
* relying on potentially-incomplete patientData.
|
|
242
|
+
*/
|
|
243
|
+
onConversationChange?: (conversation: Conversation | null) => void;
|
|
188
244
|
/** Custom class name for the outer container */
|
|
189
245
|
className?: string;
|
|
190
246
|
/** Custom inline styles for the outer container */
|
|
@@ -194,7 +250,7 @@ interface CollabPanelProps {
|
|
|
194
250
|
* Full collaboration panel: patient header + pinned bar + message thread + input.
|
|
195
251
|
* Supports reply, pin/unpin, and (optionally) seen-by indicators.
|
|
196
252
|
*/
|
|
197
|
-
declare function CollabPanel({ orderId, patientData, participantIds, showSeenBy, onBack, hidePatientName, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
253
|
+
declare function CollabPanel({ orderId, patientData, participantIds, showSeenBy, onBack, hidePatientName, onConversationChange, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
198
254
|
|
|
199
255
|
interface CollabPopupProps {
|
|
200
256
|
/** Order ID for this conversation */
|
|
@@ -209,6 +265,14 @@ interface CollabPopupProps {
|
|
|
209
265
|
onClose: () => void;
|
|
210
266
|
/** Optional back navigation — renders a ← button in the title bar when provided */
|
|
211
267
|
onBack?: () => void;
|
|
268
|
+
/**
|
|
269
|
+
* When provided, the minimize button calls this callback instead of
|
|
270
|
+
* toggling the popup's own shrink-to-titlebar state. Hosts use this
|
|
271
|
+
* to minimize the popup to an external chip / dock. With this set the
|
|
272
|
+
* minimize button always shows the minimize glyph (no expand state),
|
|
273
|
+
* since the host owns the open/minimized lifecycle.
|
|
274
|
+
*/
|
|
275
|
+
onMinimize?: () => void;
|
|
212
276
|
/** Initial position (defaults to bottom-right) */
|
|
213
277
|
initialPosition?: {
|
|
214
278
|
x: number;
|
|
@@ -224,7 +288,7 @@ interface CollabPopupProps {
|
|
|
224
288
|
* Draggable floating chat popup — drop-in replacement for DraggableChatPopup.
|
|
225
289
|
* Renders a CollabPanel inside a movable, resizable container.
|
|
226
290
|
*/
|
|
227
|
-
declare function CollabPopup({ orderId, patientData, participantIds, isOpen, onClose, onBack, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
291
|
+
declare function CollabPopup({ orderId, patientData, participantIds, isOpen, onClose, onBack, onMinimize, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
228
292
|
|
|
229
293
|
interface CollabInlineProps {
|
|
230
294
|
orderId: string;
|
|
@@ -257,8 +321,6 @@ interface CollabInboxProps {
|
|
|
257
321
|
initialConversationId?: string;
|
|
258
322
|
/** Optional callback when the user selects a conversation */
|
|
259
323
|
onSelectConversation?: (item: ConversationListItem$1) => void;
|
|
260
|
-
/** Title for the sidebar */
|
|
261
|
-
title?: string;
|
|
262
324
|
className?: string;
|
|
263
325
|
style?: React.CSSProperties;
|
|
264
326
|
}
|
|
@@ -269,7 +331,7 @@ interface CollabInboxProps {
|
|
|
269
331
|
* Uses the same CollabPanel as the floating popup, so all features
|
|
270
332
|
* (reply, pin, seen-by, DICOM, voice, attachments) are available.
|
|
271
333
|
*/
|
|
272
|
-
declare function CollabInbox({ initialConversationId, onSelectConversation,
|
|
334
|
+
declare function CollabInbox({ initialConversationId, onSelectConversation, className, style, }: CollabInboxProps): react_jsx_runtime.JSX.Element;
|
|
273
335
|
|
|
274
336
|
type MessageCallback = (message: Message) => void;
|
|
275
337
|
type TypingCallback = (event: TypingEvent) => void;
|
|
@@ -365,6 +427,13 @@ interface CollabContextValue {
|
|
|
365
427
|
config: CollabConfig;
|
|
366
428
|
apiBaseUrl: string;
|
|
367
429
|
totalUnread: number;
|
|
430
|
+
/**
|
|
431
|
+
* Per-conversation unread counts, keyed by conversation ID. Updated
|
|
432
|
+
* live via the user_notifications channel's unread_update push, so
|
|
433
|
+
* surfaces like a minimized-chat chip can reflect changes without
|
|
434
|
+
* mounting their own useConversation.
|
|
435
|
+
*/
|
|
436
|
+
unreadCounts: Record<string, number>;
|
|
368
437
|
/** Batched preview lookup — coalesces calls within a microtask */
|
|
369
438
|
requestPreview: (orderId: string) => Promise<ConversationPreview | null>;
|
|
370
439
|
/** Invalidate a cached preview (e.g. when a new message arrives) */
|
|
@@ -642,14 +711,16 @@ interface ConversationListProps {
|
|
|
642
711
|
isLoading: boolean;
|
|
643
712
|
error: string | null;
|
|
644
713
|
onSelect: (item: ConversationListItem$1) => void;
|
|
645
|
-
/** Optional title shown above the list */
|
|
646
|
-
title?: string;
|
|
647
714
|
className?: string;
|
|
648
715
|
}
|
|
649
716
|
/**
|
|
650
|
-
* Scrollable
|
|
717
|
+
* Scrollable inbox of conversations. Unread/All tabs (with count pills)
|
|
718
|
+
* sit at the top, followed by a search field with a focus-within ring.
|
|
719
|
+
* On first data load with any unread items the inbox auto-defaults to
|
|
720
|
+
* the Unread tab so triage starts on what matters. Empty/loading/error
|
|
721
|
+
* states are illustrated and descriptive rather than terse one-liners.
|
|
651
722
|
*/
|
|
652
|
-
declare function ConversationList({ conversations, selectedId, isLoading, error, onSelect,
|
|
723
|
+
declare function ConversationList({ conversations, selectedId, isLoading, error, onSelect, className, }: ConversationListProps): react_jsx_runtime.JSX.Element;
|
|
653
724
|
|
|
654
725
|
interface ConversationListItemProps {
|
|
655
726
|
item: ConversationListItem$1;
|
|
@@ -658,8 +729,21 @@ interface ConversationListItemProps {
|
|
|
658
729
|
className?: string;
|
|
659
730
|
}
|
|
660
731
|
/**
|
|
661
|
-
* Single row in the inbox sidebar
|
|
662
|
-
*
|
|
732
|
+
* Single row in the inbox sidebar.
|
|
733
|
+
*
|
|
734
|
+
* Three-row layout (top-to-bottom):
|
|
735
|
+
* 1. Patient/channel name + relative time
|
|
736
|
+
* 2. Study type + monospace `MRN <patientId>` (surfaced from the
|
|
737
|
+
* snapshot; either field is optional and the row collapses if both
|
|
738
|
+
* are missing)
|
|
739
|
+
* 3. Last message preview (sender prefix in stronger weight) + unread
|
|
740
|
+
* count badge on the right
|
|
741
|
+
*
|
|
742
|
+
* Active row gets a 4px brand-color left-border accent + tinted background.
|
|
743
|
+
* The avatar is a 52px **square** tile (16px rounded corners) with brand-
|
|
744
|
+
* coloured fill and white initials — easier to scan than a circle at this
|
|
745
|
+
* size and consistent across the inbox without depending on any case
|
|
746
|
+
* status field we don't model.
|
|
663
747
|
*/
|
|
664
748
|
declare function ConversationListItem({ item, isSelected, onClick, className, }: ConversationListItemProps): react_jsx_runtime.JSX.Element;
|
|
665
749
|
|
|
@@ -676,6 +760,20 @@ interface PatientHeaderProps {
|
|
|
676
760
|
displayName?: string;
|
|
677
761
|
className?: string;
|
|
678
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* "Case card" header that sits below the window title bar. Tinted blue-50
|
|
765
|
+
* background to set it apart from the conversation body. Renders a row
|
|
766
|
+
* of labelled key-value columns (label uppercase on top, value below) for
|
|
767
|
+
* the clinical context the host passed in, with the action buttons
|
|
768
|
+
* (View DICOM + Settings) right-aligned.
|
|
769
|
+
*
|
|
770
|
+
* Used in two layouts:
|
|
771
|
+
* - Popup path (`hideName=true`): the surrounding title bar already
|
|
772
|
+
* shows the patient name, so we render the case card only.
|
|
773
|
+
* - Compact-inbox path (`hideName=false`): the panel is a full-page
|
|
774
|
+
* experience and there's no outer title, so we still show the name +
|
|
775
|
+
* back button stacked above the case card.
|
|
776
|
+
*/
|
|
679
777
|
declare function PatientHeader({ patientData, onOpenDicom, onOpenSettings, onBack, hideName, displayName, className, }: PatientHeaderProps): react_jsx_runtime.JSX.Element;
|
|
680
778
|
|
|
681
779
|
interface MessageListHandle {
|
|
@@ -857,6 +955,34 @@ interface ParticipantsListProps {
|
|
|
857
955
|
}
|
|
858
956
|
declare function ParticipantsList({ participants, currentUserId, isAdmin, onRemoveUser, className, }: ParticipantsListProps): react_jsx_runtime.JSX.Element;
|
|
859
957
|
|
|
958
|
+
/**
|
|
959
|
+
* Shared style tokens + the global stylesheet the package injects once per
|
|
960
|
+
* page.
|
|
961
|
+
*
|
|
962
|
+
* Top-level wrappers (CollabPopup, CollabPanel, CollabInline, CollabInbox)
|
|
963
|
+
* import {@link FONT_STACK} so every surface renders with the same font
|
|
964
|
+
* stack, even when the package is mounted inside an iframe whose
|
|
965
|
+
* surrounding document doesn't set one.
|
|
966
|
+
*
|
|
967
|
+
* Themeable tokens (brand + semantic colors + the font stack) are emitted
|
|
968
|
+
* as CSS custom properties on `:root` so host apps can override them via
|
|
969
|
+
* `CollabConfig.theme` (see {@link applyThemeOverrides}). Non-themeable
|
|
970
|
+
* tokens (neutrals, slate, spacing, radius, sizes) live as inline values
|
|
971
|
+
* in core/theme.ts and stay constant.
|
|
972
|
+
*
|
|
973
|
+
* The prefers-contrast / prefers-reduced-motion adjustments are emitted
|
|
974
|
+
* inside the same stylesheet so they apply wherever a `natoe-colab-root`
|
|
975
|
+
* wrapper is mounted.
|
|
976
|
+
*/
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Apply a host-supplied theme by setting CSS custom properties on the
|
|
980
|
+
* document root. Keys missing from `theme` have their previously-set
|
|
981
|
+
* override cleared so toggling overrides back to undefined returns the
|
|
982
|
+
* default — never leaves stale values behind.
|
|
983
|
+
*/
|
|
984
|
+
declare function applyThemeOverrides(theme: Theme | undefined): void;
|
|
985
|
+
|
|
860
986
|
/** Phoenix channel event names — must match backend channel implementation */
|
|
861
987
|
declare const EVENTS: {
|
|
862
988
|
readonly MESSAGE_NEW: "message:new";
|
|
@@ -895,4 +1021,4 @@ declare const SUPPORTED_IMAGE_TYPES: string[];
|
|
|
895
1021
|
/** Max file size in bytes (20MB) */
|
|
896
1022
|
declare const MAX_FILE_SIZE: number;
|
|
897
1023
|
|
|
898
|
-
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, TYPING_DEBOUNCE_MS, type TypingEvent, type UserRole, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|
|
1024
|
+
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, THEME_DEFAULTS, THEME_VAR, TYPING_DEBOUNCE_MS, type Theme, type TypingEvent, type UserRole, applyThemeOverrides, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|