@nice2dev/ui-communication 1.0.2

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.
@@ -0,0 +1,697 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+
3
+ export type NiceAccessMode = 'read' | 'write' | 'none';
4
+ export interface NiceCommunicationBaseProps {
5
+ className?: string;
6
+ style?: CSSProperties;
7
+ id?: string;
8
+ title?: string;
9
+ 'data-testid'?: string;
10
+ accessMode?: NiceAccessMode;
11
+ }
12
+ export type PresenceStatus = 'online' | 'away' | 'busy' | 'dnd' | 'offline' | 'invisible' | 'unknown';
13
+ export interface PresenceInfo {
14
+ status: PresenceStatus;
15
+ statusMessage?: string;
16
+ lastSeenAt?: Date;
17
+ }
18
+ export type UserRole = 'owner' | 'admin' | 'member' | 'guest' | 'bot';
19
+ export interface CommunicationUser {
20
+ id: string;
21
+ name: string;
22
+ displayName?: string;
23
+ avatarUrl?: string;
24
+ email?: string;
25
+ presence: PresenceInfo;
26
+ role?: UserRole;
27
+ timezone?: string;
28
+ isBot?: boolean;
29
+ phone?: string;
30
+ }
31
+ export interface TeamMember extends CommunicationUser {
32
+ teamRole: 'owner' | 'admin' | 'member' | 'guest';
33
+ joinedAt?: Date;
34
+ }
35
+ export type MessageContentType = 'text' | 'rich' | 'markdown' | 'file' | 'image' | 'video' | 'audio' | 'code' | 'system' | 'call-event' | 'meeting-invite' | 'poll' | 'gif' | 'sticker';
36
+ export type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
37
+ export interface MessageReaction {
38
+ emoji: string;
39
+ count: number;
40
+ userIds: string[];
41
+ mine?: boolean;
42
+ }
43
+ export interface MessageAttachment {
44
+ id: string;
45
+ type: 'file' | 'image' | 'video' | 'audio';
46
+ name: string;
47
+ url: string;
48
+ size: number;
49
+ mimeType: string;
50
+ thumbnailUrl?: string;
51
+ width?: number;
52
+ height?: number;
53
+ duration?: number;
54
+ }
55
+ export interface MessageMention {
56
+ userId?: string;
57
+ channelId?: string;
58
+ teamId?: string;
59
+ type: 'user' | 'channel' | 'team' | 'everyone' | 'here';
60
+ displayText: string;
61
+ offset: number;
62
+ length: number;
63
+ }
64
+ export interface PollOption {
65
+ id: string;
66
+ text: string;
67
+ votes: number;
68
+ voterIds: string[];
69
+ }
70
+ export interface PollData {
71
+ question: string;
72
+ options: PollOption[];
73
+ allowMultiple: boolean;
74
+ isAnonymous: boolean;
75
+ expiresAt?: Date;
76
+ isClosed: boolean;
77
+ }
78
+ export interface CodeSnippet {
79
+ language: string;
80
+ code: string;
81
+ filename?: string;
82
+ }
83
+ export interface ChatMessage {
84
+ id: string;
85
+ conversationId: string;
86
+ channelId?: string;
87
+ authorId: string;
88
+ content: string;
89
+ contentType: MessageContentType;
90
+ timestamp: Date;
91
+ editedAt?: Date;
92
+ status: MessageStatus;
93
+ reactions?: MessageReaction[];
94
+ attachments?: MessageAttachment[];
95
+ mentions?: MessageMention[];
96
+ thread?: ChatMessage[];
97
+ threadCount?: number;
98
+ replyToId?: string;
99
+ replyTo?: Pick<ChatMessage, 'id' | 'authorId' | 'content'>;
100
+ isPinned?: boolean;
101
+ isForwarded?: boolean;
102
+ isDeleted?: boolean;
103
+ pollData?: PollData;
104
+ codeSnippet?: CodeSnippet;
105
+ callEventData?: CallEventData;
106
+ metadata?: Record<string, unknown>;
107
+ }
108
+ export interface CallEventData {
109
+ callId: string;
110
+ type: 'started' | 'ended' | 'missed' | 'declined';
111
+ callType: 'audio' | 'video';
112
+ duration?: number;
113
+ participantIds: string[];
114
+ }
115
+ export type ConversationType = 'dm' | 'group' | 'channel' | 'meeting';
116
+ export interface Conversation {
117
+ id: string;
118
+ type: ConversationType;
119
+ name?: string;
120
+ avatarUrl?: string;
121
+ description?: string;
122
+ participantIds: string[];
123
+ lastMessage?: ChatMessage;
124
+ unreadCount: number;
125
+ mentionCount: number;
126
+ isPinned: boolean;
127
+ isMuted: boolean;
128
+ isArchived: boolean;
129
+ createdAt: Date;
130
+ updatedAt: Date;
131
+ metadata?: Record<string, unknown>;
132
+ }
133
+ export type ChannelType = 'general' | 'private' | 'shared' | 'announcement' | 'info';
134
+ export interface Channel {
135
+ id: string;
136
+ teamId: string;
137
+ name: string;
138
+ description?: string;
139
+ type: ChannelType;
140
+ isPinned: boolean;
141
+ isMuted: boolean;
142
+ isArchived: boolean;
143
+ isPrivate: boolean;
144
+ unreadCount: number;
145
+ mentionCount: number;
146
+ memberCount: number;
147
+ createdAt: Date;
148
+ topicSetBy?: string;
149
+ topic?: string;
150
+ }
151
+ export interface Team {
152
+ id: string;
153
+ name: string;
154
+ avatarUrl?: string;
155
+ description?: string;
156
+ channels: Channel[];
157
+ members: TeamMember[];
158
+ ownerId: string;
159
+ isPrivate: boolean;
160
+ createdAt: Date;
161
+ }
162
+ export type CallStatus = 'idle' | 'ringing' | 'connecting' | 'active' | 'on-hold' | 'ended' | 'missed' | 'declined';
163
+ export type CallType = 'audio' | 'video';
164
+ export interface CallParticipant {
165
+ user: CommunicationUser;
166
+ isMuted: boolean;
167
+ isCameraOff: boolean;
168
+ isScreenSharing: boolean;
169
+ isSpeaking: boolean;
170
+ isHandRaised: boolean;
171
+ stream?: MediaStream;
172
+ screenStream?: MediaStream;
173
+ connectionQuality: 'excellent' | 'good' | 'fair' | 'poor' | 'none';
174
+ }
175
+ export interface CallSession {
176
+ id: string;
177
+ type: CallType;
178
+ conversationId?: string;
179
+ channelId?: string;
180
+ participants: CallParticipant[];
181
+ status: CallStatus;
182
+ startedAt?: Date;
183
+ endedAt?: Date;
184
+ duration?: number;
185
+ isRecording: boolean;
186
+ isTranscribing: boolean;
187
+ pinnedParticipantId?: string;
188
+ layout: 'grid' | 'spotlight' | 'sidebar';
189
+ }
190
+ export interface IncomingCall {
191
+ callId: string;
192
+ callType: CallType;
193
+ caller: CommunicationUser;
194
+ conversationId?: string;
195
+ startedAt: Date;
196
+ }
197
+ export interface Meeting {
198
+ id: string;
199
+ title: string;
200
+ description?: string;
201
+ organizerId: string;
202
+ participantIds: string[];
203
+ scheduledStart: Date;
204
+ scheduledEnd: Date;
205
+ joinUrl?: string;
206
+ isRecurring?: boolean;
207
+ channelId?: string;
208
+ teamId?: string;
209
+ }
210
+ export interface IceServerConfig {
211
+ urls: string | string[];
212
+ username?: string;
213
+ credential?: string;
214
+ }
215
+ export interface RTCTransportConfig {
216
+ iceServers?: IceServerConfig[];
217
+ signalingUrl?: string;
218
+ iceTransportPolicy?: RTCIceTransportPolicy;
219
+ maxBitrate?: {
220
+ audio?: number;
221
+ video?: number;
222
+ screen?: number;
223
+ };
224
+ }
225
+ export type TransportType = 'webrtc' | 'sfu' | 'mock' | 'custom';
226
+ export type CommunicationMode = 'bubble' | 'chat' | 'messenger' | 'workspace' | 'call' | 'conference' | 'whiteboard';
227
+ export interface CommunicationCallbacks {
228
+ onSendMessage?: (conversationId: string, content: string, contentType?: MessageContentType, attachments?: File[]) => void | Promise<void>;
229
+ onEditMessage?: (messageId: string, content: string) => void | Promise<void>;
230
+ onDeleteMessage?: (messageId: string) => void | Promise<void>;
231
+ onReactToMessage?: (messageId: string, emoji: string) => void | Promise<void>;
232
+ onPinMessage?: (messageId: string) => void | Promise<void>;
233
+ onStartCall?: (participantIds: string[], type: CallType) => void | Promise<void>;
234
+ onAcceptCall?: (callId: string) => void | Promise<void>;
235
+ onDeclineCall?: (callId: string) => void | Promise<void>;
236
+ onEndCall?: (callId: string) => void | Promise<void>;
237
+ onMuteAudio?: (muted: boolean) => void;
238
+ onMuteVideo?: (muted: boolean) => void;
239
+ onStartScreenShare?: () => void | Promise<void>;
240
+ onStopScreenShare?: () => void;
241
+ onRaiseHand?: (raised: boolean) => void;
242
+ onCreateConversation?: (participantIds: string[], type: ConversationType, name?: string) => void | Promise<void>;
243
+ onMarkAsRead?: (conversationId: string) => void | Promise<void>;
244
+ onLoadMoreMessages?: (conversationId: string, beforeId: string) => void | Promise<void>;
245
+ onOpenMeeting?: (meetingId: string) => void;
246
+ onJoinMeeting?: (meetingId: string) => void | Promise<void>;
247
+ onModeChange?: (mode: CommunicationMode) => void;
248
+ }
249
+ export interface NiceCommunicationProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
250
+ mode: CommunicationMode;
251
+ currentUser: CommunicationUser;
252
+ users: CommunicationUser[];
253
+ conversations?: Conversation[];
254
+ messages?: Record<string, ChatMessage[]>;
255
+ activeConversationId?: string;
256
+ teams?: Team[];
257
+ channels?: Channel[];
258
+ activeChannelId?: string;
259
+ activeTeamId?: string;
260
+ meetings?: Meeting[];
261
+ activeCall?: CallSession;
262
+ incomingCall?: IncomingCall;
263
+ transport?: TransportType;
264
+ rtcConfig?: RTCTransportConfig;
265
+ bubblePosition?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
266
+ bubbleLabel?: string;
267
+ placeholder?: string;
268
+ maxMessageLength?: number;
269
+ showTypingIndicators?: boolean;
270
+ enableReactions?: boolean;
271
+ enableThreads?: boolean;
272
+ enableAttachments?: boolean;
273
+ enablePolls?: boolean;
274
+ enableCodeSnippets?: boolean;
275
+ enableScreenSharing?: boolean;
276
+ enableRecording?: boolean;
277
+ enableTranscription?: boolean;
278
+ enableMeetings?: boolean;
279
+ enableGifs?: boolean;
280
+ enableWhiteboard?: boolean;
281
+ storageConfig?: StorageConfig;
282
+ encryptionConfig?: EncryptionConfig;
283
+ theme?: 'light' | 'dark' | 'auto';
284
+ locale?: string;
285
+ }
286
+ export interface NicePresenceIndicatorProps extends NiceCommunicationBaseProps {
287
+ status: PresenceStatus;
288
+ size?: 'xs' | 'sm' | 'md' | 'lg';
289
+ showLabel?: boolean;
290
+ showTooltip?: boolean;
291
+ }
292
+ export interface NiceChatWindowProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
293
+ conversation: Conversation;
294
+ messages: ChatMessage[];
295
+ users: CommunicationUser[];
296
+ currentUser: CommunicationUser;
297
+ isLoading?: boolean;
298
+ hasMore?: boolean;
299
+ showHeader?: boolean;
300
+ showUserAvatars?: boolean;
301
+ enableReactions?: boolean;
302
+ enableThreads?: boolean;
303
+ enableAttachments?: boolean;
304
+ enablePolls?: boolean;
305
+ placeholder?: string;
306
+ maxMessageLength?: number;
307
+ }
308
+ export interface NiceMessengerProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
309
+ conversations: Conversation[];
310
+ messages: Record<string, ChatMessage[]>;
311
+ users: CommunicationUser[];
312
+ currentUser: CommunicationUser;
313
+ activeConversationId?: string;
314
+ teams?: Team[];
315
+ enableGroupConversations?: boolean;
316
+ showPresence?: boolean;
317
+ enableSearch?: boolean;
318
+ }
319
+ export interface NiceCallScreenProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
320
+ session: CallSession;
321
+ currentUser: CommunicationUser;
322
+ localStream?: MediaStream;
323
+ enableScreenSharing?: boolean;
324
+ enableRecording?: boolean;
325
+ }
326
+ export interface NiceVideoConferenceProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
327
+ session: CallSession;
328
+ currentUser: CommunicationUser;
329
+ localStream?: MediaStream;
330
+ enableScreenSharing?: boolean;
331
+ enableRecording?: boolean;
332
+ enableTranscription?: boolean;
333
+ enableRaiseHand?: boolean;
334
+ maxGridCols?: number;
335
+ }
336
+ export interface NiceChannelViewProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
337
+ channel: Channel;
338
+ messages: ChatMessage[];
339
+ users: CommunicationUser[];
340
+ currentUser: CommunicationUser;
341
+ team?: Team;
342
+ isLoading?: boolean;
343
+ hasMore?: boolean;
344
+ enableThreads?: boolean;
345
+ enableReactions?: boolean;
346
+ enableAttachments?: boolean;
347
+ enablePolls?: boolean;
348
+ }
349
+ export interface NiceTeamsWorkspaceProps extends NiceCommunicationBaseProps, CommunicationCallbacks {
350
+ currentUser: CommunicationUser;
351
+ users: CommunicationUser[];
352
+ teams: Team[];
353
+ conversations: Conversation[];
354
+ messages: Record<string, ChatMessage[]>;
355
+ activeCall?: CallSession;
356
+ incomingCall?: IncomingCall;
357
+ meetings?: Meeting[];
358
+ transport?: TransportType;
359
+ rtcConfig?: RTCTransportConfig;
360
+ enableCalls?: boolean;
361
+ enableMeetings?: boolean;
362
+ enableScreenSharing?: boolean;
363
+ enableWhiteboard?: boolean;
364
+ storageConfig?: StorageConfig;
365
+ encryptionConfig?: EncryptionConfig;
366
+ }
367
+ export type EncryptionAlgorithm = 'none' | 'AES-GCM-256' | 'AES-GCM-128' | 'ChaCha20-Poly1305' | 'E2E-ECDH-P384';
368
+ export type EncryptionScope = 'messages' | 'attachments' | 'whiteboard' | 'recordings' | 'documents' | 'calls' | 'presence' | 'all';
369
+ export interface EncryptionScopeConfig {
370
+ scope: EncryptionScope;
371
+ algorithm: EncryptionAlgorithm;
372
+ enabled: boolean;
373
+ }
374
+ export interface EncryptionConfig {
375
+ /** Master switch — if false nothing is encrypted */
376
+ enabled: boolean;
377
+ /** Default algorithm for unspecified scopes */
378
+ defaultAlgorithm: EncryptionAlgorithm;
379
+ /** Per-scope overrides */
380
+ scopeOverrides?: EncryptionScopeConfig[];
381
+ /** Key-exchange endpoint for E2E-ECDH */
382
+ keyExchangeUrl?: string;
383
+ /** Externally provided symmetric key (base64-encoded raw bytes) */
384
+ keyMaterial?: string;
385
+ /** Show lock icon in UI when encryption is active */
386
+ showIndicator?: boolean;
387
+ }
388
+ export type RetentionUnit = 'days' | 'weeks' | 'months' | 'years' | 'forever';
389
+ export interface RetentionPeriod {
390
+ value: number;
391
+ unit: RetentionUnit;
392
+ }
393
+ export type RetentionDataType = 'messages' | 'attachments' | 'whiteboard-snapshots' | 'recordings' | 'transcripts' | 'documents' | 'call-logs' | 'audit-logs';
394
+ export interface RetentionRule {
395
+ dataType: RetentionDataType;
396
+ /** How long data is active / searchable */
397
+ activePeriod: RetentionPeriod;
398
+ /** Grace period in archive before final deletion (undefined = no archive) */
399
+ archivePeriod?: RetentionPeriod;
400
+ /** Permanently delete data after the archive period */
401
+ deleteAfterArchive: boolean;
402
+ /** Users can delete their own records */
403
+ userCanDelete: boolean;
404
+ /** Freeze deletion for legal-hold investigations */
405
+ legalHoldEnabled?: boolean;
406
+ }
407
+ export interface IStorageAdapter {
408
+ save(key: string, data: unknown, expiresAt?: Date): Promise<void>;
409
+ load(key: string): Promise<unknown>;
410
+ delete(key: string): Promise<void>;
411
+ list(prefix: string): Promise<string[]>;
412
+ clear(prefix?: string): Promise<void>;
413
+ }
414
+ export interface StorageConfig {
415
+ provider: 'indexeddb' | 'localstorage' | 'server' | 'custom';
416
+ /** Base URL for server provider */
417
+ serverUrl?: string;
418
+ authToken?: string;
419
+ retentionRules: RetentionRule[];
420
+ encryption?: EncryptionConfig;
421
+ /** Total quota in bytes (0 = unlimited) */
422
+ quota?: number;
423
+ customAdapter?: IStorageAdapter;
424
+ }
425
+ export type RecordingState = 'idle' | 'recording' | 'paused' | 'processing' | 'ready' | 'failed';
426
+ export interface TranscriptWord {
427
+ word: string;
428
+ startMs: number;
429
+ endMs: number;
430
+ confidence: number;
431
+ }
432
+ export interface TranscriptSegment {
433
+ id: string;
434
+ speakerId: string;
435
+ speakerName: string;
436
+ text: string;
437
+ startMs: number;
438
+ endMs: number;
439
+ confidence: number;
440
+ words?: TranscriptWord[];
441
+ }
442
+ export interface RecordingSession {
443
+ id: string;
444
+ sessionType: 'call' | 'meeting' | 'whiteboard' | 'screen';
445
+ callId?: string;
446
+ meetingId?: string;
447
+ whiteboardId?: string;
448
+ startedAt: Date;
449
+ endedAt?: Date;
450
+ durationMs?: number;
451
+ state: RecordingState;
452
+ blob?: Blob;
453
+ url?: string;
454
+ size?: number;
455
+ mimeType: string;
456
+ transcript?: TranscriptSegment[];
457
+ participants: string[];
458
+ title?: string;
459
+ }
460
+ export type WhiteboardToolType = 'pen' | 'highlighter' | 'eraser' | 'select' | 'line' | 'arrow' | 'rect' | 'ellipse' | 'triangle' | 'text' | 'sticky' | 'image' | 'laser' | 'frame';
461
+ export type WhiteboardObjectType = 'stroke' | 'shape' | 'text' | 'sticky' | 'image' | 'frame' | 'connector';
462
+ export interface WhiteboardPoint {
463
+ x: number;
464
+ y: number;
465
+ pressure?: number;
466
+ }
467
+ export interface WhiteboardBaseObject {
468
+ id: string;
469
+ type: WhiteboardObjectType;
470
+ x: number;
471
+ y: number;
472
+ width: number;
473
+ height: number;
474
+ rotation: number;
475
+ zIndex: number;
476
+ layerId?: string;
477
+ locked: boolean;
478
+ visible: boolean;
479
+ createdBy: string;
480
+ createdAt: Date;
481
+ updatedBy?: string;
482
+ updatedAt?: Date;
483
+ metadata?: Record<string, unknown>;
484
+ }
485
+ export interface WhiteboardStroke extends WhiteboardBaseObject {
486
+ type: 'stroke';
487
+ points: WhiteboardPoint[];
488
+ color: string;
489
+ strokeWidth: number;
490
+ opacity: number;
491
+ tool: 'pen' | 'highlighter';
492
+ }
493
+ export interface WhiteboardShape extends WhiteboardBaseObject {
494
+ type: 'shape';
495
+ shape: 'rect' | 'ellipse' | 'triangle' | 'diamond' | 'hexagon' | 'star';
496
+ fillColor?: string;
497
+ strokeColor: string;
498
+ strokeWidth: number;
499
+ opacity: number;
500
+ }
501
+ export interface WhiteboardTextObject extends WhiteboardBaseObject {
502
+ type: 'text';
503
+ text: string;
504
+ fontSize: number;
505
+ fontFamily: string;
506
+ fontWeight: 'normal' | 'bold';
507
+ fontStyle: 'normal' | 'italic';
508
+ textAlign: 'left' | 'center' | 'right';
509
+ color: string;
510
+ backgroundColor?: string;
511
+ }
512
+ export interface WhiteboardStickyNote extends WhiteboardBaseObject {
513
+ type: 'sticky';
514
+ text: string;
515
+ backgroundColor: string;
516
+ textColor: string;
517
+ fontSize: number;
518
+ authorId: string;
519
+ }
520
+ export interface WhiteboardImage extends WhiteboardBaseObject {
521
+ type: 'image';
522
+ url: string;
523
+ dataUrl?: string;
524
+ originalWidth: number;
525
+ originalHeight: number;
526
+ }
527
+ export interface WhiteboardFrame extends WhiteboardBaseObject {
528
+ type: 'frame';
529
+ name: string;
530
+ backgroundColor?: string;
531
+ borderColor?: string;
532
+ childIds: string[];
533
+ }
534
+ export interface WhiteboardConnector extends WhiteboardBaseObject {
535
+ type: 'connector';
536
+ points: WhiteboardPoint[];
537
+ fromObjectId?: string;
538
+ toObjectId?: string;
539
+ strokeColor: string;
540
+ strokeWidth: number;
541
+ arrowStart: 'none' | 'arrow' | 'circle' | 'diamond';
542
+ arrowEnd: 'none' | 'arrow' | 'circle' | 'diamond';
543
+ label?: string;
544
+ curved: boolean;
545
+ }
546
+ export type WhiteboardObject = WhiteboardStroke | WhiteboardShape | WhiteboardTextObject | WhiteboardStickyNote | WhiteboardImage | WhiteboardFrame | WhiteboardConnector;
547
+ export interface WhiteboardLayer {
548
+ id: string;
549
+ name: string;
550
+ visible: boolean;
551
+ locked: boolean;
552
+ objectIds: string[];
553
+ }
554
+ export interface WhiteboardCollaborator {
555
+ user: CommunicationUser;
556
+ cursorX: number;
557
+ cursorY: number;
558
+ color: string;
559
+ selectedObjectIds: string[];
560
+ activeTool: WhiteboardToolType;
561
+ lastSeenAt: Date;
562
+ }
563
+ export interface WhiteboardViewport {
564
+ x: number;
565
+ y: number;
566
+ scale: number;
567
+ }
568
+ export interface WhiteboardSession {
569
+ id: string;
570
+ title: string;
571
+ channelId?: string;
572
+ conversationId?: string;
573
+ meetingId?: string;
574
+ objects: Record<string, WhiteboardObject>;
575
+ layers: WhiteboardLayer[];
576
+ collaborators: Record<string, WhiteboardCollaborator>;
577
+ viewport: WhiteboardViewport;
578
+ width: number;
579
+ height: number;
580
+ backgroundColor: string;
581
+ gridEnabled: boolean;
582
+ gridSize: number;
583
+ snapEnabled: boolean;
584
+ createdAt: Date;
585
+ updatedAt: Date;
586
+ ownerId: string;
587
+ permissions: 'view' | 'comment' | 'edit';
588
+ }
589
+ export type WhiteboardOpType = 'object:add' | 'object:update' | 'object:delete' | 'object:move' | 'cursor:move' | 'selection:change' | 'layer:add' | 'layer:update' | 'layer:delete' | 'viewport:sync' | 'undo' | 'redo';
590
+ export interface WhiteboardOperation {
591
+ id: string;
592
+ sessionId: string;
593
+ type: WhiteboardOpType;
594
+ userId: string;
595
+ timestamp: Date;
596
+ payload: unknown;
597
+ vectorClock?: Record<string, number>;
598
+ }
599
+ export interface NiceWhiteboardProps extends NiceCommunicationBaseProps {
600
+ session: WhiteboardSession;
601
+ currentUser: CommunicationUser;
602
+ /** Called whenever the whiteboard emits an operation to broadcast */
603
+ onOperation?: (op: WhiteboardOperation) => void;
604
+ /** Remote operations to apply (from other participants) */
605
+ remoteOperations?: WhiteboardOperation[];
606
+ readonly?: boolean;
607
+ enableLayers?: boolean;
608
+ enableExport?: boolean;
609
+ enableImport?: boolean;
610
+ enableTemplates?: boolean;
611
+ /** Show cursor laser pointer for presentations */
612
+ enableLaserPointer?: boolean;
613
+ /** Integration: render a VectorEditor pane */
614
+ enableVectorEditor?: boolean;
615
+ /** Integration: render a DiagramEditor pane */
616
+ enableDiagramEditor?: boolean;
617
+ onExport?: (format: 'png' | 'svg' | 'json' | 'pdf', data: string | Blob) => void;
618
+ onSessionUpdate?: (session: WhiteboardSession) => void;
619
+ storageConfig?: StorageConfig;
620
+ }
621
+ export interface NiceStorageSettingsProps extends NiceCommunicationBaseProps {
622
+ storageConfig: StorageConfig;
623
+ encryptionConfig?: EncryptionConfig;
624
+ onStorageConfigChange?: (config: StorageConfig) => void;
625
+ onEncryptionConfigChange?: (config: EncryptionConfig) => void;
626
+ /** In bytes — for quota usage display */
627
+ currentUsageBytes?: number;
628
+ showEncryption?: boolean;
629
+ showRetention?: boolean;
630
+ showQuota?: boolean;
631
+ }
632
+ export interface NiceRecordingPanelProps extends NiceCommunicationBaseProps {
633
+ recordings?: RecordingSession[];
634
+ activeRecordingId?: string;
635
+ activeRecording?: RecordingSession;
636
+ /** Session type for new recordings */
637
+ sessionType?: RecordingSession['sessionType'];
638
+ onRecordingStart?: () => void;
639
+ onRecordingStop?: () => void;
640
+ onRecordingPause?: () => void;
641
+ onRecordingResume?: () => void;
642
+ onRecordingDelete?: (recordingId: string) => void;
643
+ onRecordingDownload?: (recordingId: string) => void;
644
+ /** @deprecated Use onRecordingStart */ onStartRecording?: (sessionType: RecordingSession['sessionType'], title?: string) => void;
645
+ /** @deprecated Use onRecordingStop */ onStopRecording?: (recordingId: string) => void;
646
+ /** @deprecated Use onRecordingPause */ onPauseRecording?: (recordingId: string) => void;
647
+ /** @deprecated */ onResumeRecording?: (recordingId: string) => void;
648
+ /** @deprecated */ onDeleteRecording?: (recordingId: string) => void;
649
+ /** @deprecated */ onDownloadRecording?: (recordingId: string) => void;
650
+ onPlayRecording?: (recordingId: string) => void;
651
+ onViewTranscript?: (recordingId: string) => void;
652
+ canRecord?: boolean;
653
+ maxRecordingDurationMs?: number;
654
+ storageConfig?: StorageConfig;
655
+ }
656
+ export type CollaborativeEditorType = 'vector' | 'pixel' | 'diagram' | 'document' | 'whiteboard';
657
+ export interface CollaborativeEditorParticipant {
658
+ user: CommunicationUser;
659
+ color: string;
660
+ /** Cursor X in editor-local coordinates */
661
+ cursorX?: number;
662
+ /** Cursor Y in editor-local coordinates */
663
+ cursorY?: number;
664
+ cursorPosition?: unknown;
665
+ selection?: unknown;
666
+ /** Whether the participant is actively editing vs. just viewing */
667
+ isActive?: boolean;
668
+ /** Human-readable region label on the canvas (e.g. "Layer 2") */
669
+ editingRegion?: string;
670
+ lastSeenAt: Date;
671
+ }
672
+ export interface NiceCollaborativeEditorProps extends NiceCommunicationBaseProps {
673
+ editorType: CollaborativeEditorType;
674
+ sessionId: string;
675
+ currentUser: CommunicationUser;
676
+ participants?: CollaborativeEditorParticipant[];
677
+ /** Called when local user makes an edit — broadcast payload to peers */
678
+ onOperation?: (op: unknown) => void;
679
+ /** Remote operations to apply */
680
+ remoteOperations?: unknown[];
681
+ isReadOnly?: boolean;
682
+ showParticipants?: boolean;
683
+ /** Whether to render remote cursor overlays */
684
+ showCursors?: boolean;
685
+ /** Number of operations queued for remote broadcast */
686
+ pendingOperations?: number;
687
+ /** Number of unresolved merge conflicts */
688
+ conflictCount?: number;
689
+ onParticipantJoin?: (userId: string) => void;
690
+ onParticipantLeave?: (userId: string) => void;
691
+ /** Called when local cursor moves (x, y in editor coords) */
692
+ onCursorMove?: (x: number, y: number) => void;
693
+ onParticipantClick?: (userId: string) => void;
694
+ storageConfig?: StorageConfig;
695
+ /** Editor element to render inside the collaboration overlay */
696
+ children?: ReactNode;
697
+ }