@wordpress/core-data 7.40.1 → 7.40.2-next.v.202602241322.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/actions.cjs +23 -29
- package/build/actions.cjs.map +2 -2
- package/build/awareness/block-lookup.cjs +103 -0
- package/build/awareness/block-lookup.cjs.map +7 -0
- package/build/awareness/post-editor-awareness.cjs +45 -7
- package/build/awareness/post-editor-awareness.cjs.map +3 -3
- package/build/entities.cjs +60 -63
- package/build/entities.cjs.map +2 -2
- package/build/entity-types/icon.cjs +19 -0
- package/build/entity-types/icon.cjs.map +7 -0
- package/build/entity-types/index.cjs.map +1 -1
- package/build/hooks/use-post-editor-awareness-state.cjs +12 -8
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/private-actions.cjs +0 -8
- package/build/private-actions.cjs.map +2 -2
- package/build/private-apis.cjs +1 -1
- package/build/private-apis.cjs.map +1 -1
- package/build/private-selectors.cjs +1 -9
- package/build/private-selectors.cjs.map +2 -2
- package/build/reducer.cjs +0 -10
- package/build/reducer.cjs.map +2 -2
- package/build/resolvers.cjs +101 -113
- package/build/resolvers.cjs.map +2 -2
- package/build/selectors.cjs.map +2 -2
- package/build/sync.cjs +0 -3
- package/build/sync.cjs.map +2 -2
- package/build/types.cjs.map +1 -1
- package/build/utils/crdt-selection.cjs +1 -1
- package/build/utils/crdt-selection.cjs.map +2 -2
- package/build/utils/crdt-user-selections.cjs +78 -22
- package/build/utils/crdt-user-selections.cjs.map +3 -3
- package/build-module/actions.mjs +23 -29
- package/build-module/actions.mjs.map +2 -2
- package/build-module/awareness/block-lookup.mjs +77 -0
- package/build-module/awareness/block-lookup.mjs.map +7 -0
- package/build-module/awareness/post-editor-awareness.mjs +47 -8
- package/build-module/awareness/post-editor-awareness.mjs.map +3 -3
- package/build-module/entities.mjs +60 -63
- package/build-module/entities.mjs.map +2 -2
- package/build-module/entity-types/icon.mjs +1 -0
- package/build-module/entity-types/icon.mjs.map +7 -0
- package/build-module/hooks/use-post-editor-awareness-state.mjs +10 -6
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/private-actions.mjs +0 -7
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/private-apis.mjs +2 -2
- package/build-module/private-apis.mjs.map +1 -1
- package/build-module/private-selectors.mjs +2 -12
- package/build-module/private-selectors.mjs.map +2 -2
- package/build-module/reducer.mjs +0 -9
- package/build-module/reducer.mjs.map +2 -2
- package/build-module/resolvers.mjs +101 -112
- package/build-module/resolvers.mjs.map +2 -2
- package/build-module/selectors.mjs.map +2 -2
- package/build-module/sync.mjs +0 -2
- package/build-module/sync.mjs.map +2 -2
- package/build-module/utils/crdt-selection.mjs +1 -1
- package/build-module/utils/crdt-selection.mjs.map +2 -2
- package/build-module/utils/crdt-user-selections.mjs +77 -22
- package/build-module/utils/crdt-user-selections.mjs.map +2 -2
- package/build-types/actions.d.ts.map +1 -1
- package/build-types/awareness/block-lookup.d.ts +29 -0
- package/build-types/awareness/block-lookup.d.ts.map +1 -0
- package/build-types/awareness/post-editor-awareness.d.ts +18 -5
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/awareness/test/block-lookup.d.ts +2 -0
- package/build-types/awareness/test/block-lookup.d.ts.map +1 -0
- package/build-types/entities.d.ts +16 -0
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/entity-types/icon.d.ts +25 -0
- package/build-types/entity-types/icon.d.ts.map +1 -0
- package/build-types/entity-types/index.d.ts +3 -2
- package/build-types/entity-types/index.d.ts.map +1 -1
- package/build-types/hooks/use-post-editor-awareness-state.d.ts +11 -6
- package/build-types/hooks/use-post-editor-awareness-state.d.ts.map +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/private-actions.d.ts +0 -8
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/private-selectors.d.ts +1 -8
- package/build-types/private-selectors.d.ts.map +1 -1
- package/build-types/reducer.d.ts +0 -11
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/resolvers.d.ts +0 -3
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/selectors.d.ts +0 -6
- package/build-types/selectors.d.ts.map +1 -1
- package/build-types/sync.d.ts +2 -2
- package/build-types/sync.d.ts.map +1 -1
- package/build-types/types.d.ts +13 -5
- package/build-types/types.d.ts.map +1 -1
- package/build-types/utils/crdt-selection.d.ts.map +1 -1
- package/build-types/utils/crdt-user-selections.d.ts +21 -4
- package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
- package/build-types/utils/test/crdt-user-selections.d.ts +2 -0
- package/build-types/utils/test/crdt-user-selections.d.ts.map +1 -0
- package/package.json +18 -18
- package/src/actions.js +39 -45
- package/src/awareness/block-lookup.ts +169 -0
- package/src/awareness/post-editor-awareness.ts +68 -11
- package/src/awareness/test/block-lookup.ts +504 -0
- package/src/awareness/test/post-editor-awareness.ts +662 -38
- package/src/entities.js +63 -66
- package/src/entity-types/icon.ts +30 -0
- package/src/entity-types/index.ts +3 -0
- package/src/hooks/test/use-post-editor-awareness-state.ts +21 -14
- package/src/hooks/use-post-editor-awareness-state.ts +22 -13
- package/src/private-actions.js +0 -14
- package/src/private-apis.js +2 -2
- package/src/private-selectors.ts +3 -22
- package/src/reducer.js +0 -17
- package/src/resolvers.js +137 -156
- package/src/selectors.ts +0 -7
- package/src/sync.ts +0 -2
- package/src/test/resolvers.js +109 -1
- package/src/types.ts +22 -5
- package/src/utils/crdt-selection.ts +3 -1
- package/src/utils/crdt-user-selections.ts +129 -47
- package/src/utils/test/crdt-user-selections.ts +894 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
+
import { select } from '@wordpress/data';
|
|
4
5
|
import { Y } from '@wordpress/sync';
|
|
6
|
+
// @ts-ignore No exported types for block editor store selectors.
|
|
7
|
+
import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Internal dependencies
|
|
@@ -11,6 +14,7 @@ import type { YPostRecord } from './crdt';
|
|
|
11
14
|
import type { YBlock, YBlocks } from './crdt-blocks';
|
|
12
15
|
import { getRootMap } from './crdt-utils';
|
|
13
16
|
import type {
|
|
17
|
+
AbsoluteBlockIndexPath,
|
|
14
18
|
WPBlockSelection,
|
|
15
19
|
SelectionState,
|
|
16
20
|
SelectionNone,
|
|
@@ -35,6 +39,11 @@ export enum SelectionType {
|
|
|
35
39
|
/**
|
|
36
40
|
* Converts WordPress block editor selection to a SelectionState.
|
|
37
41
|
*
|
|
42
|
+
* Uses getBlockPathForLocalClientId to locate blocks in the Yjs document by
|
|
43
|
+
* their tree position (index path) rather than clientId, since clientIds may
|
|
44
|
+
* differ between the block-editor store and the Yjs document (e.g. in "Show
|
|
45
|
+
* Template" mode).
|
|
46
|
+
*
|
|
38
47
|
* @param selectionStart - The start position of the selection
|
|
39
48
|
* @param selectionEnd - The end position of the selection
|
|
40
49
|
* @param yDoc - The Yjs document
|
|
@@ -46,15 +55,15 @@ export function getSelectionState(
|
|
|
46
55
|
yDoc: Y.Doc
|
|
47
56
|
): SelectionState {
|
|
48
57
|
const ymap = getRootMap< YPostRecord >( yDoc, CRDT_RECORD_MAP_KEY );
|
|
49
|
-
const yBlocks = ymap.get( 'blocks' )
|
|
58
|
+
const yBlocks = ymap.get( 'blocks' );
|
|
50
59
|
|
|
51
60
|
const isSelectionEmpty = Object.keys( selectionStart ).length === 0;
|
|
52
61
|
const noSelection: SelectionNone = {
|
|
53
62
|
type: SelectionType.None,
|
|
54
63
|
};
|
|
55
64
|
|
|
56
|
-
if ( isSelectionEmpty ) {
|
|
57
|
-
// Case 1: No selection
|
|
65
|
+
if ( isSelectionEmpty || ! yBlocks ) {
|
|
66
|
+
// Case 1: No selection, or no blocks in the document.
|
|
58
67
|
return noSelection;
|
|
59
68
|
}
|
|
60
69
|
|
|
@@ -70,9 +79,18 @@ export function getSelectionState(
|
|
|
70
79
|
|
|
71
80
|
if ( isSelectionAWholeBlock ) {
|
|
72
81
|
// Case 2: A whole block is selected.
|
|
82
|
+
const path = getBlockPathForLocalClientId( selectionStart.clientId );
|
|
83
|
+
const blockPosition = path
|
|
84
|
+
? createRelativePositionForBlockPath( path, yBlocks )
|
|
85
|
+
: null;
|
|
86
|
+
|
|
87
|
+
if ( ! blockPosition ) {
|
|
88
|
+
return noSelection;
|
|
89
|
+
}
|
|
90
|
+
|
|
73
91
|
return {
|
|
74
92
|
type: SelectionType.WholeBlock,
|
|
75
|
-
|
|
93
|
+
blockPosition,
|
|
76
94
|
};
|
|
77
95
|
} else if ( isCursorOnly ) {
|
|
78
96
|
// Case 3: Cursor only, no text selected
|
|
@@ -85,7 +103,6 @@ export function getSelectionState(
|
|
|
85
103
|
|
|
86
104
|
return {
|
|
87
105
|
type: SelectionType.Cursor,
|
|
88
|
-
blockId: selectionStart.clientId,
|
|
89
106
|
cursorPosition,
|
|
90
107
|
};
|
|
91
108
|
} else if ( isSelectionInOneBlock ) {
|
|
@@ -103,13 +120,12 @@ export function getSelectionState(
|
|
|
103
120
|
|
|
104
121
|
return {
|
|
105
122
|
type: SelectionType.SelectionInOneBlock,
|
|
106
|
-
blockId: selectionStart.clientId,
|
|
107
123
|
cursorStartPosition,
|
|
108
124
|
cursorEndPosition,
|
|
109
125
|
};
|
|
110
126
|
}
|
|
111
127
|
|
|
112
|
-
//
|
|
128
|
+
// Case 5: Selection in multiple blocks
|
|
113
129
|
const cursorStartPosition = getCursorPosition( selectionStart, yBlocks );
|
|
114
130
|
const cursorEndPosition = getCursorPosition( selectionEnd, yBlocks );
|
|
115
131
|
if ( ! cursorStartPosition || ! cursorEndPosition ) {
|
|
@@ -119,8 +135,6 @@ export function getSelectionState(
|
|
|
119
135
|
|
|
120
136
|
return {
|
|
121
137
|
type: SelectionType.SelectionInMultipleBlocks,
|
|
122
|
-
blockStartId: selectionStart.clientId,
|
|
123
|
-
blockEndId: selectionEnd.clientId,
|
|
124
138
|
cursorStartPosition,
|
|
125
139
|
cursorEndPosition,
|
|
126
140
|
};
|
|
@@ -137,7 +151,8 @@ function getCursorPosition(
|
|
|
137
151
|
selection: WPBlockSelection,
|
|
138
152
|
blocks: YBlocks
|
|
139
153
|
): CursorPosition | null {
|
|
140
|
-
const
|
|
154
|
+
const path = getBlockPathForLocalClientId( selection.clientId );
|
|
155
|
+
const block = path ? findBlockByPath( path, blocks ) : null;
|
|
141
156
|
if (
|
|
142
157
|
! block ||
|
|
143
158
|
! selection.attributeKey ||
|
|
@@ -147,7 +162,12 @@ function getCursorPosition(
|
|
|
147
162
|
}
|
|
148
163
|
|
|
149
164
|
const attributes = block.get( 'attributes' );
|
|
150
|
-
const currentYText = attributes?.get( selection.attributeKey )
|
|
165
|
+
const currentYText = attributes?.get( selection.attributeKey );
|
|
166
|
+
|
|
167
|
+
// If the attribute is not a Y.Text, return null.
|
|
168
|
+
if ( ! ( currentYText instanceof Y.Text ) ) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
151
171
|
|
|
152
172
|
const relativePosition = Y.createRelativePositionFromTypeIndex(
|
|
153
173
|
currentYText,
|
|
@@ -161,32 +181,103 @@ function getCursorPosition(
|
|
|
161
181
|
}
|
|
162
182
|
|
|
163
183
|
/**
|
|
164
|
-
*
|
|
184
|
+
* Resolves a local block-editor clientId to its index path relative to the
|
|
185
|
+
* post content blocks. This allows finding the corresponding block in the Yjs
|
|
186
|
+
* document even when clientIds differ (e.g. in "Show Template" mode where
|
|
187
|
+
* blocks are cloned).
|
|
188
|
+
*
|
|
189
|
+
* In template mode, the block tree includes template parts and wrapper blocks
|
|
190
|
+
* around a core/post-content block. The Yjs document only contains the post
|
|
191
|
+
* content blocks, so we stop the upward walk when the parent is
|
|
192
|
+
* core/post-content (its inner blocks correspond to the Yjs root blocks).
|
|
193
|
+
*
|
|
194
|
+
* @param clientId - The local block-editor clientId to resolve.
|
|
195
|
+
* @return The index path from root, or null if not resolvable.
|
|
196
|
+
*/
|
|
197
|
+
export function getBlockPathForLocalClientId(
|
|
198
|
+
clientId: string
|
|
199
|
+
): AbsoluteBlockIndexPath | null {
|
|
200
|
+
const { getBlockIndex, getBlockRootClientId, getBlockName } =
|
|
201
|
+
select( blockEditorStore );
|
|
202
|
+
|
|
203
|
+
const path: AbsoluteBlockIndexPath = [];
|
|
204
|
+
let current: string | null = clientId;
|
|
205
|
+
while ( current ) {
|
|
206
|
+
const index = getBlockIndex( current );
|
|
207
|
+
if ( index === -1 ) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
path.unshift( index );
|
|
211
|
+
const parent = getBlockRootClientId( current );
|
|
212
|
+
if ( ! parent ) {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
// If the parent is core/post-content, stop here — the Yjs doc
|
|
216
|
+
// root blocks correspond to post-content's inner blocks.
|
|
217
|
+
const parentName = getBlockName( parent );
|
|
218
|
+
if ( parentName === 'core/post-content' ) {
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
current = parent;
|
|
222
|
+
}
|
|
223
|
+
return path.length > 0 ? path : null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Find a block by navigating a tree index path in the Yjs block hierarchy.
|
|
165
228
|
*
|
|
166
|
-
* @param
|
|
167
|
-
* @param blocks
|
|
168
|
-
* @return The block if found, null otherwise.
|
|
229
|
+
* @param path - The index path, e.g. [0, 1] for blocks[0].innerBlocks[1].
|
|
230
|
+
* @param blocks - The root-level Yjs blocks array.
|
|
231
|
+
* @return The block Y.Map if found, null otherwise.
|
|
169
232
|
*/
|
|
170
|
-
function
|
|
171
|
-
|
|
233
|
+
function findBlockByPath(
|
|
234
|
+
path: AbsoluteBlockIndexPath,
|
|
172
235
|
blocks: YBlocks
|
|
173
236
|
): YBlock | null {
|
|
174
|
-
|
|
175
|
-
|
|
237
|
+
let currentBlocks = blocks;
|
|
238
|
+
for ( let i = 0; i < path.length; i++ ) {
|
|
239
|
+
if ( path[ i ] >= currentBlocks.length ) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const block = currentBlocks.get( path[ i ] );
|
|
243
|
+
if ( ! block ) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
if ( i === path.length - 1 ) {
|
|
176
247
|
return block;
|
|
177
248
|
}
|
|
249
|
+
currentBlocks =
|
|
250
|
+
block.get( 'innerBlocks' ) ?? ( new Y.Array() as YBlocks );
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
178
254
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Create a Y.RelativePosition for a block by navigating a tree index path.
|
|
257
|
+
*
|
|
258
|
+
* @param path - The index path, e.g. [0, 1] for blocks[0].innerBlocks[1].
|
|
259
|
+
* @param blocks - The root-level Yjs blocks array.
|
|
260
|
+
* @return A Y.RelativePosition for the block, or null if the path is invalid.
|
|
261
|
+
*/
|
|
262
|
+
function createRelativePositionForBlockPath(
|
|
263
|
+
path: AbsoluteBlockIndexPath,
|
|
264
|
+
blocks: YBlocks
|
|
265
|
+
): Y.RelativePosition | null {
|
|
266
|
+
let currentBlocks = blocks;
|
|
267
|
+
for ( let i = 0; i < path.length; i++ ) {
|
|
268
|
+
if ( path[ i ] >= currentBlocks.length ) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
if ( i === path.length - 1 ) {
|
|
272
|
+
return Y.createRelativePositionFromTypeIndex(
|
|
273
|
+
currentBlocks,
|
|
274
|
+
path[ i ]
|
|
275
|
+
);
|
|
187
276
|
}
|
|
277
|
+
const block = currentBlocks.get( path[ i ] );
|
|
278
|
+
currentBlocks =
|
|
279
|
+
block?.get( 'innerBlocks' ) ?? ( new Y.Array() as YBlocks );
|
|
188
280
|
}
|
|
189
|
-
|
|
190
281
|
return null;
|
|
191
282
|
}
|
|
192
283
|
|
|
@@ -210,19 +301,13 @@ export function areSelectionsStatesEqual(
|
|
|
210
301
|
return true;
|
|
211
302
|
|
|
212
303
|
case SelectionType.Cursor:
|
|
213
|
-
return (
|
|
214
|
-
selection1.
|
|
215
|
-
|
|
216
|
-
areCursorPositionsEqual(
|
|
217
|
-
selection1.cursorPosition,
|
|
218
|
-
( selection2 as SelectionCursor ).cursorPosition
|
|
219
|
-
)
|
|
304
|
+
return areCursorPositionsEqual(
|
|
305
|
+
selection1.cursorPosition,
|
|
306
|
+
( selection2 as SelectionCursor ).cursorPosition
|
|
220
307
|
);
|
|
221
308
|
|
|
222
309
|
case SelectionType.SelectionInOneBlock:
|
|
223
310
|
return (
|
|
224
|
-
selection1.blockId ===
|
|
225
|
-
( selection2 as SelectionInOneBlock ).blockId &&
|
|
226
311
|
areCursorPositionsEqual(
|
|
227
312
|
selection1.cursorStartPosition,
|
|
228
313
|
( selection2 as SelectionInOneBlock ).cursorStartPosition
|
|
@@ -235,10 +320,6 @@ export function areSelectionsStatesEqual(
|
|
|
235
320
|
|
|
236
321
|
case SelectionType.SelectionInMultipleBlocks:
|
|
237
322
|
return (
|
|
238
|
-
selection1.blockStartId ===
|
|
239
|
-
( selection2 as SelectionInMultipleBlocks ).blockStartId &&
|
|
240
|
-
selection1.blockEndId ===
|
|
241
|
-
( selection2 as SelectionInMultipleBlocks ).blockEndId &&
|
|
242
323
|
areCursorPositionsEqual(
|
|
243
324
|
selection1.cursorStartPosition,
|
|
244
325
|
( selection2 as SelectionInMultipleBlocks )
|
|
@@ -251,9 +332,9 @@ export function areSelectionsStatesEqual(
|
|
|
251
332
|
)
|
|
252
333
|
);
|
|
253
334
|
case SelectionType.WholeBlock:
|
|
254
|
-
return (
|
|
255
|
-
selection1.
|
|
256
|
-
( selection2 as SelectionWholeBlock ).
|
|
335
|
+
return Y.compareRelativePositions(
|
|
336
|
+
selection1.blockPosition,
|
|
337
|
+
( selection2 as SelectionWholeBlock ).blockPosition
|
|
257
338
|
);
|
|
258
339
|
|
|
259
340
|
default:
|
|
@@ -272,9 +353,10 @@ function areCursorPositionsEqual(
|
|
|
272
353
|
cursorPosition1: CursorPosition,
|
|
273
354
|
cursorPosition2: CursorPosition
|
|
274
355
|
): boolean {
|
|
275
|
-
const isRelativePositionEqual =
|
|
276
|
-
|
|
277
|
-
|
|
356
|
+
const isRelativePositionEqual = Y.compareRelativePositions(
|
|
357
|
+
cursorPosition1.relativePosition,
|
|
358
|
+
cursorPosition2.relativePosition
|
|
359
|
+
);
|
|
278
360
|
|
|
279
361
|
// Ensure a change in calculated absolute offset results in a treating the cursor as modified.
|
|
280
362
|
// This is necessary because Y.Text relative positions can remain the same after text changes.
|