@@ -30,10 +30,19 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
30
30
const bindingRef = useRef < MonacoBinding | null > ( null ) ;
31
31
const providerRef = useRef < WebsocketProvider | null > ( null ) ;
32
32
const ydocRef = useRef < Y . Doc | null > ( null ) ;
33
+ const yMapRef = useRef < Y . Map < string > | null > ( null ) ;
33
34
34
35
const initialiseEditor = ( roomId : string , editor : monaco . editor . IStandaloneCodeEditor , monaco : Monaco ) => {
35
36
editorRef . current = editor ;
36
37
monacoRef . current = monaco ;
38
+
39
+ initialiseLanguages ( monaco ) ;
40
+ const { yDoc, provider, yMap } = initialiseYdoc ( roomId ) ;
41
+ bindEditorToDoc ( editor , yDoc , provider ) ;
42
+ setUpObserver ( yMap ) ;
43
+ } ;
44
+
45
+ const initialiseLanguages = ( monaco : Monaco ) => {
37
46
const allLanguages = monaco . languages . getLanguages ( ) ;
38
47
39
48
// TODO: Filter all the useless ones like HTML
@@ -43,61 +52,60 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
43
52
value : lang . id
44
53
} ) )
45
54
) ;
55
+ } ;
46
56
47
- const doc = new Y . Doc ( ) ;
48
- ydocRef . current = doc ;
49
-
57
+ const initialiseYdoc = ( roomId : string ) : { yDoc : Y . Doc ; yMap : Y . Map < string > ; provider : WebsocketProvider } => {
58
+ const yDoc = new Y . Doc ( ) ;
59
+ const yMap : Y . Map < string > = yDoc . getMap ( "sharedMap" ) ;
60
+ ydocRef . current = yDoc ;
61
+ yMapRef . current = yMap ;
50
62
// TODO: Replace serverUrl once BE ready
51
63
// Test locally across browers with 'HOST=localhost PORT 1234 npx y-websocket'
52
- const provider = new WebsocketProvider ( "ws://localhost:1234" , roomId , doc ) ;
64
+ const provider = new WebsocketProvider ( "ws://localhost:1234" , roomId , yDoc ) ;
53
65
provider . on ( "status" , ( event : any ) => {
54
66
console . log ( event . status ) ;
55
67
} ) ;
56
68
providerRef . current = provider ;
57
- const type = doc . getText ( "monaco" ) ;
58
- const editorModel = editor . getModel ( ) ;
69
+ return { yDoc , yMap , provider } ;
70
+ } ;
59
71
72
+ const bindEditorToDoc = ( editor : monaco . editor . IStandaloneCodeEditor , yDoc : Y . Doc , provider : WebsocketProvider ) => {
73
+ const type = yDoc . getText ( "monaco" ) ;
74
+ const editorModel = editor . getModel ( ) ;
60
75
if ( editorModel == null ) {
61
76
toast . error ( "There was an issue with initialising the code editor" ) ;
62
77
return ;
63
78
}
64
79
const binding = new MonacoBinding ( type , editorModel , new Set ( [ editor ] ) , provider . awareness ) ;
65
80
bindingRef . current = binding ;
81
+ } ;
66
82
67
- // Initialise awareness states
68
- provider . awareness . setLocalStateField ( USER_ID , userId ) ;
69
-
70
- // TODO: initialise with correct language on page reload
71
- provider . awareness . setLocalStateField ( SELECTED_LANGUAGE , selectedLanguage ) ;
72
-
73
- provider . awareness . on ( "change" , ( { updated } : { updated : any } ) => {
74
- // On change language
75
- updated . forEach ( ( id : number ) => {
76
- const trigger = provider . awareness . getStates ( ) . get ( id ) ; // Get the user who initiated the change
77
- if ( trigger && trigger . selectedLanguage ) {
78
- // Ignore all state updates caused by the current user
79
- if ( trigger . userId !== userId ) {
80
- setSelectedLanguage ( trigger . selectedLanguage ) ;
83
+ const setUpObserver = ( yMap : Y . Map < string > ) => {
84
+ yMap . observe ( ( event ) => {
85
+ event . changes . keys . forEach ( ( change , key ) => {
86
+ if ( key === SELECTED_LANGUAGE ) {
87
+ const language = yMap . get ( SELECTED_LANGUAGE ) ;
88
+ if ( language ) {
89
+ setSelectedLanguage ( language ) ;
81
90
}
82
91
}
83
92
} ) ;
84
93
} ) ;
85
94
} ;
86
95
87
- const handleChangeLanguage = ( lang : string ) => {
88
- setSelectedLanguage ( lang ) ;
89
- providerRef . current ?. awareness . setLocalStateField ( SELECTED_LANGUAGE , lang ) ;
90
- } ;
91
96
useEffect ( ( ) => {
92
97
return ( ) => {
93
98
bindingRef . current ?. destroy ( ) ;
94
- providerRef . current ?. awareness . setLocalState ( null ) ;
95
99
providerRef . current ?. disconnect ( ) ;
96
100
editorRef . current ?. dispose ( ) ;
97
101
ydocRef . current ?. destroy ( ) ;
98
102
} ;
99
103
} , [ ] ) ;
100
104
105
+ const handleChangeLanguage = ( lang : string ) => {
106
+ yMapRef . current ?. set ( SELECTED_LANGUAGE , lang ) ;
107
+ } ;
108
+
101
109
return (
102
110
< CollaborationContext . Provider value = { { initialiseEditor, selectedLanguage, languages, handleChangeLanguage } } >
103
111
{ children }
0 commit comments