@wordpress/core-data 7.39.1-next.v.0 → 7.39.1-next.v.202602091733.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/build/awareness/awareness-state.cjs +267 -0
- package/build/awareness/awareness-state.cjs.map +7 -0
- package/build/awareness/base-awareness.cjs +14 -11
- package/build/awareness/base-awareness.cjs.map +2 -2
- package/build/awareness/config.cjs +5 -2
- package/build/awareness/config.cjs.map +2 -2
- package/build/awareness/post-editor-awareness.cjs +9 -9
- package/build/awareness/post-editor-awareness.cjs.map +2 -2
- package/build/awareness/typed-awareness.cjs +56 -0
- package/build/awareness/typed-awareness.cjs.map +7 -0
- package/build/awareness/types.cjs.map +1 -1
- package/build/awareness/utils.cjs +43 -14
- package/build/awareness/utils.cjs.map +2 -2
- package/build/entities.cjs +1 -1
- package/build/entities.cjs.map +1 -1
- package/build/hooks/use-post-editor-awareness-state.cjs +11 -11
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/index.cjs +2 -0
- package/build/index.cjs.map +2 -2
- package/build/private-apis.cjs +3 -1
- package/build/private-apis.cjs.map +2 -2
- package/build/sync.cjs +18 -6
- package/build/sync.cjs.map +3 -3
- package/build/utils/crdt-blocks.cjs +3 -2
- package/build/utils/crdt-blocks.cjs.map +3 -3
- package/build/utils/crdt-user-selections.cjs +2 -1
- package/build/utils/crdt-user-selections.cjs.map +3 -3
- package/build/utils/crdt.cjs.map +2 -2
- package/build-module/awareness/awareness-state.mjs +242 -0
- package/build-module/awareness/awareness-state.mjs.map +7 -0
- package/build-module/awareness/base-awareness.mjs +14 -11
- package/build-module/awareness/base-awareness.mjs.map +2 -2
- package/build-module/awareness/config.mjs +3 -1
- package/build-module/awareness/config.mjs.map +2 -2
- package/build-module/awareness/post-editor-awareness.mjs +9 -9
- package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
- package/build-module/awareness/typed-awareness.mjs +31 -0
- package/build-module/awareness/typed-awareness.mjs.map +7 -0
- package/build-module/awareness/utils.mjs +38 -12
- package/build-module/awareness/utils.mjs.map +2 -2
- package/build-module/entities.mjs +1 -1
- package/build-module/entities.mjs.map +1 -1
- package/build-module/hooks/use-post-editor-awareness-state.mjs +10 -10
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/index.mjs +1 -0
- package/build-module/index.mjs.map +2 -2
- package/build-module/private-apis.mjs +3 -1
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/sync.mjs +9 -3
- package/build-module/sync.mjs.map +2 -2
- package/build-module/utils/crdt-blocks.mjs +2 -1
- package/build-module/utils/crdt-blocks.mjs.map +2 -2
- package/build-module/utils/crdt-user-selections.mjs +2 -1
- package/build-module/utils/crdt-user-selections.mjs.map +2 -2
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-types/awareness/awareness-state.d.ts +125 -0
- package/build-types/awareness/awareness-state.d.ts.map +1 -0
- package/build-types/awareness/base-awareness.d.ts +9 -6
- package/build-types/awareness/base-awareness.d.ts.map +1 -1
- package/build-types/awareness/config.d.ts +4 -0
- package/build-types/awareness/config.d.ts.map +1 -1
- package/build-types/awareness/post-editor-awareness.d.ts +4 -4
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/awareness/typed-awareness.d.ts +25 -0
- package/build-types/awareness/typed-awareness.d.ts.map +1 -0
- package/build-types/awareness/types.d.ts +19 -10
- package/build-types/awareness/types.d.ts.map +1 -1
- package/build-types/awareness/utils.d.ts +14 -11
- package/build-types/awareness/utils.d.ts.map +1 -1
- package/build-types/hooks/use-post-editor-awareness-state.d.ts +6 -6
- package/build-types/hooks/use-post-editor-awareness-state.d.ts.map +1 -1
- package/build-types/index.d.ts +1 -0
- package/build-types/index.d.ts.map +1 -1
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/sync.d.ts +3 -2
- package/build-types/sync.d.ts.map +1 -1
- package/build-types/utils/crdt-blocks.d.ts.map +1 -1
- package/build-types/utils/crdt-user-selections.d.ts +1 -1
- package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts +1 -2
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/package.json +18 -18
- package/src/awareness/awareness-state.ts +342 -0
- package/src/awareness/base-awareness.ts +14 -11
- package/src/awareness/config.ts +5 -0
- package/src/awareness/post-editor-awareness.ts +11 -11
- package/src/awareness/typed-awareness.ts +44 -0
- package/src/awareness/types.ts +25 -11
- package/src/awareness/utils.ts +67 -27
- package/src/entities.js +1 -1
- package/src/hooks/use-post-editor-awareness-state.ts +21 -20
- package/src/index.js +1 -0
- package/src/private-apis.js +2 -0
- package/src/sync.ts +14 -3
- package/src/utils/crdt-blocks.ts +2 -1
- package/src/utils/crdt-user-selections.ts +3 -2
- package/src/utils/crdt.ts +1 -2
- package/src/utils/test/crdt.ts +5 -5
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
|
|
23
23
|
import type { SelectionCursor, WPBlockSelection } from '../types';
|
|
24
24
|
import type {
|
|
25
|
-
|
|
25
|
+
DebugCollaboratorData,
|
|
26
26
|
EditorState,
|
|
27
27
|
PostEditorState,
|
|
28
28
|
SerializableYItem,
|
|
@@ -47,13 +47,13 @@ export class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {
|
|
|
47
47
|
protected onSetUp(): void {
|
|
48
48
|
super.onSetUp();
|
|
49
49
|
|
|
50
|
-
this.
|
|
50
|
+
this.subscribeToCollaboratorSelectionChanges();
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
* Subscribe to
|
|
54
|
+
* Subscribe to collaborator selection changes and update the selection state.
|
|
55
55
|
*/
|
|
56
|
-
private
|
|
56
|
+
private subscribeToCollaboratorSelectionChanges(): void {
|
|
57
57
|
const {
|
|
58
58
|
getSelectionStart,
|
|
59
59
|
getSelectionEnd,
|
|
@@ -116,7 +116,7 @@ export class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
|
-
* Update the entity record with the current
|
|
119
|
+
* Update the entity record with the current collaborator's selection.
|
|
120
120
|
*
|
|
121
121
|
* @param selectionStart - The start position of the selection.
|
|
122
122
|
* @param selectionEnd - The end position of the selection.
|
|
@@ -213,14 +213,14 @@ export class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {
|
|
|
213
213
|
] )
|
|
214
214
|
);
|
|
215
215
|
|
|
216
|
-
// Build
|
|
217
|
-
const
|
|
216
|
+
// Build collaboratorMap from awareness store (all collaborators seen this session)
|
|
217
|
+
const collaboratorMapData = new Map< string, DebugCollaboratorData >(
|
|
218
218
|
Array.from( this.getSeenStates().entries() ).map(
|
|
219
|
-
( [ clientId,
|
|
219
|
+
( [ clientId, collaboratorState ] ) => [
|
|
220
220
|
String( clientId ),
|
|
221
221
|
{
|
|
222
|
-
name:
|
|
223
|
-
wpUserId:
|
|
222
|
+
name: collaboratorState.collaboratorInfo.name,
|
|
223
|
+
wpUserId: collaboratorState.collaboratorInfo.id,
|
|
224
224
|
},
|
|
225
225
|
]
|
|
226
226
|
)
|
|
@@ -264,7 +264,7 @@ export class PostEditorAwareness extends BaseAwarenessState< PostEditorState > {
|
|
|
264
264
|
return {
|
|
265
265
|
doc: docData,
|
|
266
266
|
clients: serializableClientItems,
|
|
267
|
-
|
|
267
|
+
collaboratorMap: Object.fromEntries( collaboratorMapData ),
|
|
268
268
|
};
|
|
269
269
|
}
|
|
270
270
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Awareness } from '@wordpress/sync';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { getRecordValue } from './utils';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extended Awareness class with typed state accessors.
|
|
13
|
+
*/
|
|
14
|
+
export class TypedAwareness< State extends object > extends Awareness {
|
|
15
|
+
/**
|
|
16
|
+
* Get the states from an awareness document.
|
|
17
|
+
*/
|
|
18
|
+
public getStates(): Map< number, State > {
|
|
19
|
+
return super.getStates() as Map< number, State >;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get a local state field from an awareness document.
|
|
24
|
+
* @param field
|
|
25
|
+
*/
|
|
26
|
+
public getLocalStateField< FieldName extends keyof State >(
|
|
27
|
+
field: FieldName
|
|
28
|
+
): State[ FieldName ] | null {
|
|
29
|
+
const state: State | null = this.getLocalState() as State | null;
|
|
30
|
+
return getRecordValue< State, FieldName >( state, field );
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Set a local state field on an awareness document.
|
|
35
|
+
* @param field
|
|
36
|
+
* @param value
|
|
37
|
+
*/
|
|
38
|
+
public setLocalStateField< FieldName extends string & keyof State >(
|
|
39
|
+
field: FieldName,
|
|
40
|
+
value: State[ FieldName ]
|
|
41
|
+
): void {
|
|
42
|
+
super.setLocalStateField( field, value );
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/awareness/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { Y } from '@wordpress/sync';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal dependencies
|
|
@@ -9,7 +9,7 @@ import type { EnhancedState, Y } from '@wordpress/sync';
|
|
|
9
9
|
import type { SelectionState } from '../types';
|
|
10
10
|
import type { User } from '../entity-types';
|
|
11
11
|
|
|
12
|
-
export type
|
|
12
|
+
export type CollaboratorInfo = Pick<
|
|
13
13
|
User< 'view' >,
|
|
14
14
|
'id' | 'name' | 'slug' | 'avatar_urls'
|
|
15
15
|
> & {
|
|
@@ -19,16 +19,16 @@ export type UserInfo = Pick<
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* This base state represents the presence of the
|
|
23
|
-
* extended to include additional state describing the
|
|
22
|
+
* This base state represents the presence of the collaborator. We expect it to be
|
|
23
|
+
* extended to include additional state describing the collaborator's current activity.
|
|
24
24
|
* This state must be serializable and compact.
|
|
25
25
|
*/
|
|
26
26
|
export interface BaseState {
|
|
27
|
-
|
|
27
|
+
collaboratorInfo: CollaboratorInfo;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* The editor state includes information about the
|
|
31
|
+
* The editor state includes information about the collaborator's current selection.
|
|
32
32
|
*/
|
|
33
33
|
export interface EditorState {
|
|
34
34
|
selection: SelectionState;
|
|
@@ -42,21 +42,30 @@ export interface PostEditorState extends BaseState {
|
|
|
42
42
|
editorState?: EditorState;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* An enhanced state includes additional metadata about the collaborator's connection.
|
|
47
|
+
*/
|
|
48
|
+
export type EnhancedState< State > = State & {
|
|
49
|
+
clientId: number;
|
|
50
|
+
isConnected: boolean;
|
|
51
|
+
isMe: boolean;
|
|
52
|
+
};
|
|
53
|
+
|
|
45
54
|
/**
|
|
46
55
|
* An enhanced post editor awareness state includes additional metadata about
|
|
47
|
-
* the
|
|
56
|
+
* the collaborator and their connection.
|
|
48
57
|
*/
|
|
49
58
|
export type PostEditorAwarenessState = EnhancedState< PostEditorState >;
|
|
50
59
|
|
|
51
|
-
// WordPress
|
|
52
|
-
export type
|
|
53
|
-
wpUserId:
|
|
60
|
+
// WordPress collaborator info for debug export (subset of CollaboratorInfo)
|
|
61
|
+
export type DebugCollaboratorData = Pick< CollaboratorInfo, 'name' > & {
|
|
62
|
+
wpUserId: CollaboratorInfo[ 'id' ];
|
|
54
63
|
};
|
|
55
64
|
|
|
56
65
|
export interface YDocDebugData {
|
|
57
66
|
doc: Record< string, unknown >;
|
|
58
67
|
clients: Record< number, Array< SerializableYItem > >;
|
|
59
|
-
|
|
68
|
+
collaboratorMap: Record< string, DebugCollaboratorData >;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
// Type for serializable left/right item references to avoid deep nesting
|
|
@@ -81,3 +90,8 @@ export type SerializableYItem = Pick<
|
|
|
81
90
|
left: SerializableYItemRef | null;
|
|
82
91
|
right: SerializableYItemRef | null;
|
|
83
92
|
};
|
|
93
|
+
|
|
94
|
+
export type EqualityFieldCheck< State, FieldName extends keyof State > = (
|
|
95
|
+
value1?: State[ FieldName ],
|
|
96
|
+
value2?: State[ FieldName ]
|
|
97
|
+
) => boolean;
|
package/src/awareness/utils.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Internal dependencies
|
|
3
3
|
*/
|
|
4
4
|
import type { User } from '../entity-types';
|
|
5
|
-
import type {
|
|
5
|
+
import type { CollaboratorInfo } from './types';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* The color palette for the
|
|
8
|
+
* The color palette for the collaborator highlight.
|
|
9
9
|
*/
|
|
10
10
|
const COLOR_PALETTE = [
|
|
11
11
|
'#3858E9', // blueberry
|
|
@@ -30,13 +30,13 @@ function generateRandomInt( min: number, max: number ): number {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Get a unique
|
|
33
|
+
* Get a unique collaborator color from the palette, or generate a variation if none are available.
|
|
34
34
|
* If the previously used color is available from localStorage, use it.
|
|
35
35
|
*
|
|
36
36
|
* @param existingColors - Colors that are already in use.
|
|
37
|
-
* @return The new
|
|
37
|
+
* @return The new collaborator color, in hex format.
|
|
38
38
|
*/
|
|
39
|
-
function
|
|
39
|
+
function getNewCollaboratorColor( existingColors: string[] ): string {
|
|
40
40
|
const availableColors = COLOR_PALETTE.filter(
|
|
41
41
|
( color ) => ! existingColors.includes( color )
|
|
42
42
|
);
|
|
@@ -114,46 +114,86 @@ function getBrowserName(): string {
|
|
|
114
114
|
return browserName;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
export function areMapsEqual< Key, Value >(
|
|
118
|
+
map1: Map< Key, Value >,
|
|
119
|
+
map2: Map< Key, Value >,
|
|
120
|
+
comparatorFn: ( value1: Value, value2: Value ) => boolean
|
|
121
|
+
): boolean {
|
|
122
|
+
if ( map1.size !== map2.size ) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for ( const [ key, value1 ] of map1.entries() ) {
|
|
127
|
+
if ( ! map2.has( key ) ) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if ( ! comparatorFn( value1, map2.get( key )! ) ) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
117
139
|
/**
|
|
118
|
-
* Check if two
|
|
140
|
+
* Check if two collaborator infos are equal.
|
|
119
141
|
*
|
|
120
|
-
* @param
|
|
121
|
-
* @param
|
|
122
|
-
* @return True if the
|
|
142
|
+
* @param collaboratorInfo1 - The first collaborator info.
|
|
143
|
+
* @param collaboratorInfo2 - The second collaborator info.
|
|
144
|
+
* @return True if the collaborator infos are equal, false otherwise.
|
|
123
145
|
*/
|
|
124
|
-
export function
|
|
125
|
-
|
|
126
|
-
|
|
146
|
+
export function areCollaboratorInfosEqual(
|
|
147
|
+
collaboratorInfo1?: CollaboratorInfo,
|
|
148
|
+
collaboratorInfo2?: CollaboratorInfo
|
|
127
149
|
): boolean {
|
|
128
|
-
if ( !
|
|
129
|
-
return
|
|
150
|
+
if ( ! collaboratorInfo1 || ! collaboratorInfo2 ) {
|
|
151
|
+
return collaboratorInfo1 === collaboratorInfo2;
|
|
130
152
|
}
|
|
131
153
|
|
|
132
|
-
if (
|
|
154
|
+
if (
|
|
155
|
+
Object.keys( collaboratorInfo1 ).length !==
|
|
156
|
+
Object.keys( collaboratorInfo2 ).length
|
|
157
|
+
) {
|
|
133
158
|
return false;
|
|
134
159
|
}
|
|
135
160
|
|
|
136
|
-
return Object.entries(
|
|
137
|
-
// Update this function with any non-primitive fields added to
|
|
138
|
-
return value ===
|
|
161
|
+
return Object.entries( collaboratorInfo1 ).every( ( [ key, value ] ) => {
|
|
162
|
+
// Update this function with any non-primitive fields added to CollaboratorInfo.
|
|
163
|
+
return value === collaboratorInfo2[ key as keyof CollaboratorInfo ];
|
|
139
164
|
} );
|
|
140
165
|
}
|
|
141
166
|
|
|
142
167
|
/**
|
|
143
|
-
* Generate a
|
|
168
|
+
* Generate a collaborator info object from a current collaborator and a list of existing colors.
|
|
144
169
|
*
|
|
145
|
-
* @param
|
|
146
|
-
* @param existingColors
|
|
147
|
-
* @return The
|
|
170
|
+
* @param currentCollaborator - The current collaborator.
|
|
171
|
+
* @param existingColors - The existing colors.
|
|
172
|
+
* @return The collaborator info object.
|
|
148
173
|
*/
|
|
149
|
-
export function
|
|
150
|
-
|
|
174
|
+
export function generateCollaboratorInfo(
|
|
175
|
+
currentCollaborator: User< 'view' >,
|
|
151
176
|
existingColors: string[]
|
|
152
|
-
):
|
|
177
|
+
): CollaboratorInfo {
|
|
153
178
|
return {
|
|
154
|
-
...
|
|
179
|
+
...currentCollaborator,
|
|
155
180
|
browserType: getBrowserName(),
|
|
156
|
-
color:
|
|
181
|
+
color: getNewCollaboratorColor( existingColors ),
|
|
157
182
|
enteredAt: Date.now(),
|
|
158
183
|
};
|
|
159
184
|
}
|
|
185
|
+
|
|
186
|
+
export function getRecordValue< RecordType, Key extends keyof RecordType >(
|
|
187
|
+
obj: unknown,
|
|
188
|
+
key: Key
|
|
189
|
+
): RecordType[ Key ] | null {
|
|
190
|
+
if ( 'object' === typeof obj && null !== obj && key in obj ) {
|
|
191
|
+
return ( obj as RecordType )[ key ];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function getTypedKeys< T extends object >( obj: T ): Array< keyof T > {
|
|
198
|
+
return Object.keys( obj ) as Array< keyof T >;
|
|
199
|
+
}
|
package/src/entities.js
CHANGED
|
@@ -374,7 +374,7 @@ async function loadPostTypeEntities() {
|
|
|
374
374
|
*
|
|
375
375
|
* @param {import('@wordpress/sync').CRDTDoc} ydoc
|
|
376
376
|
* @param {import('@wordpress/sync').ObjectID} objectId
|
|
377
|
-
* @return {import('@wordpress/sync').
|
|
377
|
+
* @return {import('@wordpress/sync').Awareness} Awareness instance
|
|
378
378
|
*/
|
|
379
379
|
createAwareness: ( ydoc, objectId ) => {
|
|
380
380
|
const kind = 'postType';
|
|
@@ -8,43 +8,44 @@ import { useEffect, useState } from '@wordpress/element';
|
|
|
8
8
|
*/
|
|
9
9
|
import { getSyncManager } from '../sync';
|
|
10
10
|
import type {
|
|
11
|
-
PostEditorAwarenessState as
|
|
11
|
+
PostEditorAwarenessState as ActiveCollaborator,
|
|
12
12
|
YDocDebugData,
|
|
13
13
|
} from '../awareness/types';
|
|
14
14
|
import type { SelectionCursor } from '../types';
|
|
15
15
|
import type { PostEditorAwareness } from '../awareness/post-editor-awareness';
|
|
16
16
|
|
|
17
17
|
interface AwarenessState {
|
|
18
|
-
|
|
18
|
+
activeCollaborators: ActiveCollaborator[];
|
|
19
19
|
getAbsolutePositionIndex: ( selection: SelectionCursor ) => number | null;
|
|
20
20
|
getDebugData: () => YDocDebugData;
|
|
21
|
-
|
|
21
|
+
isCurrentCollaboratorDisconnected: boolean;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const defaultState: AwarenessState = {
|
|
25
|
-
|
|
25
|
+
activeCollaborators: [],
|
|
26
26
|
getAbsolutePositionIndex: () => null,
|
|
27
27
|
getDebugData: () => ( {
|
|
28
28
|
doc: {},
|
|
29
29
|
clients: {},
|
|
30
|
-
|
|
30
|
+
collaboratorMap: {},
|
|
31
31
|
} ),
|
|
32
|
-
|
|
32
|
+
isCurrentCollaboratorDisconnected: false,
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
function getAwarenessState(
|
|
36
36
|
awareness: PostEditorAwareness,
|
|
37
|
-
newState?:
|
|
37
|
+
newState?: ActiveCollaborator[]
|
|
38
38
|
): AwarenessState {
|
|
39
|
-
const
|
|
39
|
+
const activeCollaborators = newState ?? awareness.getCurrentState();
|
|
40
40
|
|
|
41
41
|
return {
|
|
42
|
-
|
|
42
|
+
activeCollaborators,
|
|
43
43
|
getAbsolutePositionIndex: ( selection: SelectionCursor ) =>
|
|
44
44
|
awareness.getAbsolutePositionIndex( selection ),
|
|
45
45
|
getDebugData: () => awareness.getDebugData(),
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
isCurrentCollaboratorDisconnected:
|
|
47
|
+
activeCollaborators.find( ( collaborator ) => collaborator.isMe )
|
|
48
|
+
?.isConnected === false,
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -78,7 +79,7 @@ function usePostEditorAwarenessState(
|
|
|
78
79
|
setState( getAwarenessState( awareness ) );
|
|
79
80
|
|
|
80
81
|
const unsubscribe = awareness?.onStateChange(
|
|
81
|
-
( newState:
|
|
82
|
+
( newState: ActiveCollaborator[] ) => {
|
|
82
83
|
setState( getAwarenessState( awareness, newState ) );
|
|
83
84
|
}
|
|
84
85
|
);
|
|
@@ -90,17 +91,17 @@ function usePostEditorAwarenessState(
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
|
-
* Hook to get the active
|
|
94
|
+
* Hook to get the active collaborators for a post editor.
|
|
94
95
|
*
|
|
95
96
|
* @param postId - The ID of the post.
|
|
96
97
|
* @param postType - The type of the post.
|
|
97
|
-
* @return {
|
|
98
|
+
* @return {ActiveCollaborator[]} The active collaborators.
|
|
98
99
|
*/
|
|
99
|
-
export function
|
|
100
|
+
export function useActiveCollaborators(
|
|
100
101
|
postId: number | null,
|
|
101
102
|
postType: string | null
|
|
102
|
-
):
|
|
103
|
-
return usePostEditorAwarenessState( postId, postType ).
|
|
103
|
+
): ActiveCollaborator[] {
|
|
104
|
+
return usePostEditorAwarenessState( postId, postType ).activeCollaborators;
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
/**
|
|
@@ -133,16 +134,16 @@ export function useGetDebugData(
|
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
/**
|
|
136
|
-
* Hook to check if the current
|
|
137
|
+
* Hook to check if the current collaborator is disconnected.
|
|
137
138
|
*
|
|
138
139
|
* @param postId - The ID of the post.
|
|
139
140
|
* @param postType - The type of the post.
|
|
140
|
-
* @return {boolean} Whether the current
|
|
141
|
+
* @return {boolean} Whether the current collaborator is disconnected.
|
|
141
142
|
*/
|
|
142
143
|
export function useIsDisconnected(
|
|
143
144
|
postId: number | null,
|
|
144
145
|
postType: string | null
|
|
145
146
|
): boolean {
|
|
146
147
|
return usePostEditorAwarenessState( postId, postType )
|
|
147
|
-
.
|
|
148
|
+
.isCurrentCollaboratorDisconnected;
|
|
148
149
|
}
|
package/src/index.js
CHANGED
|
@@ -136,6 +136,7 @@ register( store ); // Register store after unlocking private selectors to allow
|
|
|
136
136
|
export { default as EntityProvider } from './entity-provider';
|
|
137
137
|
export * from './entity-provider';
|
|
138
138
|
export * from './entity-types';
|
|
139
|
+
export * from './awareness/types';
|
|
139
140
|
export * from './fetch';
|
|
140
141
|
export * from './hooks';
|
|
141
142
|
export * from './private-apis';
|
package/src/private-apis.js
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { useEntityRecordsWithPermissions } from './hooks/use-entity-records';
|
|
5
5
|
import { RECEIVE_INTERMEDIATE_RESULTS } from './utils';
|
|
6
|
+
import { useActiveCollaborators } from './hooks/use-post-editor-awareness-state';
|
|
6
7
|
import { lock } from './lock-unlock';
|
|
7
8
|
|
|
8
9
|
export const privateApis = {};
|
|
9
10
|
lock( privateApis, {
|
|
10
11
|
useEntityRecordsWithPermissions,
|
|
11
12
|
RECEIVE_INTERMEDIATE_RESULTS,
|
|
13
|
+
useActiveCollaborators,
|
|
12
14
|
} );
|
package/src/sync.ts
CHANGED
|
@@ -2,16 +2,27 @@
|
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
+
privateApis as syncPrivateApis,
|
|
6
|
+
type SyncManager,
|
|
7
|
+
} from '@wordpress/sync';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import { unlock } from './lock-unlock';
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
createSyncManager,
|
|
16
|
+
Delta,
|
|
5
17
|
CRDT_DOC_META_PERSISTENCE_KEY,
|
|
6
18
|
CRDT_RECORD_MAP_KEY,
|
|
7
19
|
LOCAL_EDITOR_ORIGIN,
|
|
8
20
|
LOCAL_SYNC_MANAGER_ORIGIN,
|
|
9
21
|
WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
10
|
-
|
|
11
|
-
createSyncManager,
|
|
12
|
-
} from '@wordpress/sync';
|
|
22
|
+
} = unlock( syncPrivateApis );
|
|
13
23
|
|
|
14
24
|
export {
|
|
25
|
+
Delta,
|
|
15
26
|
CRDT_DOC_META_PERSISTENCE_KEY,
|
|
16
27
|
CRDT_RECORD_MAP_KEY,
|
|
17
28
|
LOCAL_EDITOR_ORIGIN,
|
package/src/utils/crdt-blocks.ts
CHANGED
|
@@ -10,12 +10,13 @@ import fastDeepEqual from 'fast-deep-equal/es6/index.js';
|
|
|
10
10
|
// @ts-expect-error No exported types.
|
|
11
11
|
import { getBlockTypes } from '@wordpress/blocks';
|
|
12
12
|
import { RichTextData } from '@wordpress/rich-text';
|
|
13
|
-
import { Y
|
|
13
|
+
import { Y } from '@wordpress/sync';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Internal dependencies
|
|
17
17
|
*/
|
|
18
18
|
import { createYMap, type YMapRecord, type YMapWrap } from './crdt-utils';
|
|
19
|
+
import { Delta } from '../sync';
|
|
19
20
|
|
|
20
21
|
interface BlockAttributes {
|
|
21
22
|
[ key: string ]: unknown;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { Y
|
|
4
|
+
import { Y } from '@wordpress/sync';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
|
+
import { CRDT_RECORD_MAP_KEY } from '../sync';
|
|
9
10
|
import type { YPostRecord } from './crdt';
|
|
10
11
|
import type { YBlock, YBlocks } from './crdt-blocks';
|
|
11
12
|
import { getRootMap } from './crdt-utils';
|
package/src/utils/crdt.ts
CHANGED
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
* Internal dependencies
|
|
20
20
|
*/
|
|
21
21
|
import { BaseAwareness } from '../awareness/base-awareness';
|
|
22
|
-
import { type BaseState } from '../awareness/types';
|
|
23
22
|
import {
|
|
24
23
|
mergeCrdtBlocks,
|
|
25
24
|
type Block,
|
|
@@ -409,7 +408,7 @@ export function getPostChangesFromCRDTDoc(
|
|
|
409
408
|
* This default sync config can be used for entities that are flat maps of
|
|
410
409
|
* primitive values and do not require custom logic to merge changes.
|
|
411
410
|
*/
|
|
412
|
-
export const defaultSyncConfig: SyncConfig
|
|
411
|
+
export const defaultSyncConfig: SyncConfig = {
|
|
413
412
|
applyChangesToCRDTDoc: defaultApplyChangesToCRDTDoc,
|
|
414
413
|
createAwareness: ( ydoc: CRDTDoc ) => new BaseAwareness( ydoc ),
|
|
415
414
|
getChangesFromCRDTDoc: defaultGetChangesFromCRDTDoc,
|
package/src/utils/test/crdt.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
CRDT_RECORD_MAP_KEY,
|
|
6
|
-
WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
7
|
-
Y,
|
|
8
|
-
} from '@wordpress/sync';
|
|
4
|
+
import { Y } from '@wordpress/sync';
|
|
9
5
|
|
|
10
6
|
/**
|
|
11
7
|
* External dependencies
|
|
@@ -15,6 +11,10 @@ import { describe, expect, it, jest, beforeEach } from '@jest/globals';
|
|
|
15
11
|
/**
|
|
16
12
|
* Internal dependencies
|
|
17
13
|
*/
|
|
14
|
+
import {
|
|
15
|
+
CRDT_RECORD_MAP_KEY,
|
|
16
|
+
WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
17
|
+
} from '../../sync';
|
|
18
18
|
import {
|
|
19
19
|
applyPostChangesToCRDTDoc,
|
|
20
20
|
getPostChangesFromCRDTDoc,
|