@nice2dev/ui-communication 1.0.8 → 1.0.10
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/__tests__/encryptionService.test.d.ts +8 -0
- package/dist/__tests__/helpers.test.d.ts +7 -0
- package/dist/__tests__/setup.d.ts +1 -0
- package/dist/__tests__/storageService.test.d.ts +7 -0
- package/dist/__tests__/transport.test.d.ts +8 -0
- package/dist/collaboration/collaborative-datagrid.d.ts +95 -0
- package/dist/collaboration/collaborative-form.d.ts +75 -0
- package/dist/collaboration/yjs-integration.d.ts +135 -0
- package/dist/communication-controls.d.ts +369 -0
- package/dist/hooks/useCommunication.d.ts +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +4720 -2695
- package/package.json +2 -2
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file encryptionService.test.ts
|
|
3
|
+
* @description Phase A1.5 baseline coverage for the EncryptionService and the
|
|
4
|
+
* pure base64 / key-helper functions exported alongside it. Uses Node's
|
|
5
|
+
* built-in WebCrypto (`crypto.subtle`) — no network, no DOM beyond what jsdom
|
|
6
|
+
* already provides.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file transport.test.ts
|
|
3
|
+
* @description Phase A1.5 — coverage for the framework-agnostic transport
|
|
4
|
+
* factory + MockTransport event flow. Avoids real WebRTC / MediaRecorder /
|
|
5
|
+
* AudioContext APIs (not available in jsdom), focuses on the event-emitter
|
|
6
|
+
* surface and lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { CollaborationConfig } from './yjs-integration';
|
|
2
|
+
/**
|
|
3
|
+
* @file Collaborative DataGrid with CRDT
|
|
4
|
+
* @description Real-time collaborative data grid editing
|
|
5
|
+
*/
|
|
6
|
+
import * as Y from 'yjs';
|
|
7
|
+
export interface CollaborativeDataGridConfig<T> extends CollaborationConfig {
|
|
8
|
+
/** Initial rows data */
|
|
9
|
+
initialData?: T[];
|
|
10
|
+
/** Column definitions */
|
|
11
|
+
columns: CollaborativeColumnDef<T>[];
|
|
12
|
+
/** Row ID field */
|
|
13
|
+
rowIdField: keyof T;
|
|
14
|
+
}
|
|
15
|
+
export interface CollaborativeColumnDef<T> {
|
|
16
|
+
field: keyof T;
|
|
17
|
+
header: string;
|
|
18
|
+
editable?: boolean;
|
|
19
|
+
width?: number;
|
|
20
|
+
type?: 'text' | 'number' | 'boolean' | 'date' | 'select';
|
|
21
|
+
options?: {
|
|
22
|
+
value: string;
|
|
23
|
+
label: string;
|
|
24
|
+
}[];
|
|
25
|
+
}
|
|
26
|
+
export interface CellEdit<T> {
|
|
27
|
+
rowId: string;
|
|
28
|
+
field: keyof T;
|
|
29
|
+
value: unknown;
|
|
30
|
+
userId: string;
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
export interface ActiveEdit {
|
|
34
|
+
rowId: string;
|
|
35
|
+
field: string;
|
|
36
|
+
user: {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
color: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Hook for collaborative DataGrid editing
|
|
44
|
+
*/
|
|
45
|
+
export declare function useCollaborativeDataGrid<T extends Record<string, unknown>>(config: CollaborativeDataGridConfig<T>): {
|
|
46
|
+
rows: T[];
|
|
47
|
+
columns: CollaborativeColumnDef<T>[];
|
|
48
|
+
collaborators: import('./yjs-integration').CollaborationUser[];
|
|
49
|
+
isConnected: boolean;
|
|
50
|
+
isSynced: boolean;
|
|
51
|
+
activeEdits: ActiveEdit[];
|
|
52
|
+
startCellEdit: (rowId: string, field: keyof T) => void;
|
|
53
|
+
endCellEdit: () => void;
|
|
54
|
+
updateCell: (rowIndex: number, field: keyof T, value: unknown) => void;
|
|
55
|
+
addRow: (row: T) => void;
|
|
56
|
+
removeRow: (rowIndex: number) => void;
|
|
57
|
+
isCellLocked: (rowId: string, field: keyof T) => ActiveEdit | undefined;
|
|
58
|
+
getRowById: (id: string) => {
|
|
59
|
+
row: T;
|
|
60
|
+
index: number;
|
|
61
|
+
} | undefined;
|
|
62
|
+
};
|
|
63
|
+
export interface ConflictResolution<T> {
|
|
64
|
+
strategy: 'lastWriteWins' | 'firstWriteWins' | 'merge' | 'custom';
|
|
65
|
+
mergeFunction?: (local: T, remote: T) => T;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Hook for conflict resolution in collaborative editing
|
|
69
|
+
*/
|
|
70
|
+
export declare function useConflictResolution<T>(resolution: ConflictResolution<T>): {
|
|
71
|
+
resolve: (local: T, remote: T, timestamp: {
|
|
72
|
+
local: number;
|
|
73
|
+
remote: number;
|
|
74
|
+
}) => T;
|
|
75
|
+
};
|
|
76
|
+
export interface ChangeHistoryEntry<T> {
|
|
77
|
+
id: string;
|
|
78
|
+
type: 'insert' | 'update' | 'delete';
|
|
79
|
+
rowId: string;
|
|
80
|
+
field?: keyof T;
|
|
81
|
+
oldValue?: unknown;
|
|
82
|
+
newValue?: unknown;
|
|
83
|
+
user: {
|
|
84
|
+
id: string;
|
|
85
|
+
name: string;
|
|
86
|
+
};
|
|
87
|
+
timestamp: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Hook for tracking change history
|
|
91
|
+
*/
|
|
92
|
+
export declare function useChangeHistory<T>(ydoc: Y.Doc | null, rowIdField: keyof T): {
|
|
93
|
+
history: ChangeHistoryEntry<T>[];
|
|
94
|
+
clearHistory: () => void;
|
|
95
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { CollaborationConfig, CollaborationUser } from './yjs-integration';
|
|
2
|
+
|
|
3
|
+
export interface CollaborativeFormConfig<T extends Record<string, unknown>> extends CollaborationConfig {
|
|
4
|
+
/** Initial form values */
|
|
5
|
+
initialValues?: Partial<T>;
|
|
6
|
+
/** Field validation rules */
|
|
7
|
+
validation?: FormValidation<T>;
|
|
8
|
+
/** Debounce delay for syncing (ms) */
|
|
9
|
+
syncDelay?: number;
|
|
10
|
+
}
|
|
11
|
+
export type FormValidation<T> = {
|
|
12
|
+
[K in keyof T]?: (value: T[K], formValues: Partial<T>) => string | undefined;
|
|
13
|
+
};
|
|
14
|
+
export interface FieldFocus {
|
|
15
|
+
fieldName: string;
|
|
16
|
+
user: CollaborationUser;
|
|
17
|
+
}
|
|
18
|
+
export interface FormState<T> {
|
|
19
|
+
values: Partial<T>;
|
|
20
|
+
errors: Partial<Record<keyof T, string>>;
|
|
21
|
+
touched: Partial<Record<keyof T, boolean>>;
|
|
22
|
+
isDirty: boolean;
|
|
23
|
+
isValid: boolean;
|
|
24
|
+
focusedFields: FieldFocus[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Hook for collaborative form editing
|
|
28
|
+
*/
|
|
29
|
+
export declare function useCollaborativeForm<T extends Record<string, unknown>>(config: CollaborativeFormConfig<T>): {
|
|
30
|
+
values: Partial<T>;
|
|
31
|
+
errors: Partial<Record<keyof T, string>>;
|
|
32
|
+
touched: Partial<Record<keyof T, boolean>>;
|
|
33
|
+
isDirty: boolean;
|
|
34
|
+
isValid: boolean;
|
|
35
|
+
focusedFields: FieldFocus[];
|
|
36
|
+
collaborators: CollaborationUser[];
|
|
37
|
+
isConnected: boolean;
|
|
38
|
+
isSynced: boolean;
|
|
39
|
+
setFieldValue: <K extends keyof T>(fieldName: K, value: T[K]) => void;
|
|
40
|
+
setFieldTouched: (fieldName: keyof T, isTouched?: boolean) => void;
|
|
41
|
+
handleFieldFocus: (fieldName: keyof T) => void;
|
|
42
|
+
handleFieldBlur: (fieldName: keyof T) => void;
|
|
43
|
+
isFieldFocused: (fieldName: keyof T) => FieldFocus | undefined;
|
|
44
|
+
validateField: (fieldName: keyof T, value: T[typeof fieldName]) => string | undefined;
|
|
45
|
+
validateForm: () => boolean;
|
|
46
|
+
resetForm: () => void;
|
|
47
|
+
handleSubmit: (onSubmit: (values: Partial<T>) => void | Promise<void>) => (e?: React.FormEvent) => Promise<void>;
|
|
48
|
+
};
|
|
49
|
+
export interface CollaborativeFieldProps {
|
|
50
|
+
name: string;
|
|
51
|
+
focusedBy?: FieldFocus;
|
|
52
|
+
children: React.ReactNode;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Wrapper component showing collaborative field state
|
|
56
|
+
*/
|
|
57
|
+
export declare function CollaborativeFieldWrapper({ name, focusedBy, children }: CollaborativeFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
58
|
+
/**
|
|
59
|
+
* Convenience hook for individual form field
|
|
60
|
+
*/
|
|
61
|
+
export declare function useCollaborativeField<T extends Record<string, unknown>, K extends keyof T>(form: ReturnType<typeof useCollaborativeForm<T>>, fieldName: K): {
|
|
62
|
+
value: Partial<T>[K];
|
|
63
|
+
error: Partial<Record<keyof T, string>>[K] | undefined;
|
|
64
|
+
touched: Partial<Record<keyof T, boolean>>[K];
|
|
65
|
+
focusedBy: FieldFocus | undefined;
|
|
66
|
+
onChange: (newValue: T[K]) => void;
|
|
67
|
+
onFocus: () => void;
|
|
68
|
+
onBlur: () => void;
|
|
69
|
+
inputProps: {
|
|
70
|
+
value: string | NonNullable<Partial<T>[K]>;
|
|
71
|
+
onFocus: () => void;
|
|
72
|
+
onBlur: () => void;
|
|
73
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Nice2Dev Real-time Collaboration - Yjs/CRDT Integration
|
|
3
|
+
* @description Real-time collaborative editing using Yjs CRDTs
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import * as Y from 'yjs';
|
|
7
|
+
export interface CollaborationConfig {
|
|
8
|
+
/** Document ID */
|
|
9
|
+
documentId: string;
|
|
10
|
+
/** User information */
|
|
11
|
+
user: CollaborationUser;
|
|
12
|
+
/** Server URL for WebSocket */
|
|
13
|
+
serverUrl?: string;
|
|
14
|
+
/** Enable WebRTC for peer-to-peer */
|
|
15
|
+
useWebRTC?: boolean;
|
|
16
|
+
/** Enable offline persistence */
|
|
17
|
+
persistence?: boolean;
|
|
18
|
+
/** Awareness features */
|
|
19
|
+
awareness?: AwarenessConfig;
|
|
20
|
+
}
|
|
21
|
+
export interface CollaborationUser {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
color: string;
|
|
25
|
+
avatar?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface AwarenessConfig {
|
|
28
|
+
/** Update interval in ms */
|
|
29
|
+
updateInterval?: number;
|
|
30
|
+
/** Show cursors */
|
|
31
|
+
showCursors?: boolean;
|
|
32
|
+
/** Show selections */
|
|
33
|
+
showSelections?: boolean;
|
|
34
|
+
/** Show user presence */
|
|
35
|
+
showPresence?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface AwarenessState {
|
|
38
|
+
user: CollaborationUser;
|
|
39
|
+
cursor?: {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
};
|
|
43
|
+
selection?: {
|
|
44
|
+
start: number;
|
|
45
|
+
end: number;
|
|
46
|
+
};
|
|
47
|
+
field?: string;
|
|
48
|
+
lastActive: number;
|
|
49
|
+
}
|
|
50
|
+
export interface CollaborationState {
|
|
51
|
+
isConnected: boolean;
|
|
52
|
+
isSynced: boolean;
|
|
53
|
+
users: CollaborationUser[];
|
|
54
|
+
awareness: Map<number, AwarenessState>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Main collaboration hook - creates and manages a Yjs document
|
|
58
|
+
*/
|
|
59
|
+
export declare function useCollaboration(config: CollaborationConfig): {
|
|
60
|
+
ydoc: Y.Doc | null;
|
|
61
|
+
state: CollaborationState;
|
|
62
|
+
updateAwareness: (update: Partial<AwarenessState>) => void;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Hook for collaborative text editing
|
|
66
|
+
*/
|
|
67
|
+
export declare function useCollaborativeText(ydoc: Y.Doc | null, fieldName: string): {
|
|
68
|
+
value: string;
|
|
69
|
+
insert: (index: number, text: string) => void;
|
|
70
|
+
delete: (index: number, length: number) => void;
|
|
71
|
+
replace: (newValue: string) => void;
|
|
72
|
+
ytext: Y.Text | null;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Hook for collaborative arrays (e.g., table rows, list items)
|
|
76
|
+
*/
|
|
77
|
+
export declare function useCollaborativeArray<T>(ydoc: Y.Doc | null, arrayName: string): {
|
|
78
|
+
items: T[];
|
|
79
|
+
push: (...newItems: T[]) => void;
|
|
80
|
+
insert: (index: number, ...newItems: T[]) => void;
|
|
81
|
+
delete: (index: number, length?: number) => void;
|
|
82
|
+
update: (index: number, value: T) => void;
|
|
83
|
+
move: (fromIndex: number, toIndex: number) => void;
|
|
84
|
+
yarray: Y.Array<T> | null;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Hook for collaborative maps (e.g., form fields)
|
|
88
|
+
*/
|
|
89
|
+
export declare function useCollaborativeMap<T extends Record<string, unknown>>(ydoc: Y.Doc | null, mapName: string): {
|
|
90
|
+
data: Partial<T>;
|
|
91
|
+
set: <K extends keyof T>(key: K, value: T[K]) => void;
|
|
92
|
+
get: <K extends keyof T>(key: K) => T[K] | undefined;
|
|
93
|
+
delete: (key: keyof T) => void;
|
|
94
|
+
setMultiple: (updates: Partial<T>) => void;
|
|
95
|
+
ymap: Y.Map<unknown> | null;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Hook for tracking and displaying user cursors
|
|
99
|
+
*/
|
|
100
|
+
export declare function useCursorTracking(updateAwareness: (update: Partial<AwarenessState>) => void, enabled?: boolean): void;
|
|
101
|
+
/**
|
|
102
|
+
* Hook for tracking text selection
|
|
103
|
+
*/
|
|
104
|
+
export declare function useSelectionTracking(updateAwareness: (update: Partial<AwarenessState>) => void, fieldName: string, enabled?: boolean): void;
|
|
105
|
+
/**
|
|
106
|
+
* Hook for collaborative undo/redo
|
|
107
|
+
*/
|
|
108
|
+
export declare function useCollaborativeHistory(ydoc: Y.Doc | null): {
|
|
109
|
+
undo: () => void;
|
|
110
|
+
redo: () => void;
|
|
111
|
+
canUndo: boolean;
|
|
112
|
+
canRedo: boolean;
|
|
113
|
+
};
|
|
114
|
+
export interface PresenceAvatarsProps {
|
|
115
|
+
users: CollaborationUser[];
|
|
116
|
+
maxDisplay?: number;
|
|
117
|
+
size?: 'sm' | 'md' | 'lg';
|
|
118
|
+
className?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Component displaying active collaborators
|
|
122
|
+
*/
|
|
123
|
+
export declare function PresenceAvatars({ users, maxDisplay, size, className, }: PresenceAvatarsProps): import("react/jsx-runtime").JSX.Element;
|
|
124
|
+
export interface CursorOverlayProps {
|
|
125
|
+
awareness: Map<number, AwarenessState>;
|
|
126
|
+
localClientId: number;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Component displaying other users' cursors
|
|
130
|
+
*/
|
|
131
|
+
export declare function CursorOverlay({ awareness, localClientId }: CursorOverlayProps): import("react/jsx-runtime").JSX.Element;
|
|
132
|
+
export * from 'yjs';
|
|
133
|
+
export { WebsocketProvider } from 'y-websocket';
|
|
134
|
+
export { WebrtcProvider } from 'y-webrtc';
|
|
135
|
+
export { IndexeddbPersistence } from 'y-indexeddb';
|