@wordpress/core-data 7.47.0 → 7.48.1
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/CHANGELOG.md +8 -0
- package/build/awareness/block-lookup.cjs +14 -26
- package/build/awareness/block-lookup.cjs.map +2 -2
- package/build/awareness/post-editor-awareness.cjs +4 -3
- package/build/awareness/post-editor-awareness.cjs.map +2 -2
- package/build/entities.cjs +4 -2
- package/build/entities.cjs.map +2 -2
- package/build/hooks/use-post-editor-awareness-state.cjs +8 -2
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/private-actions.cjs +8 -0
- package/build/private-actions.cjs.map +2 -2
- package/build/private-selectors.cjs.map +2 -2
- package/build/reducer.cjs +13 -0
- package/build/reducer.cjs.map +2 -2
- package/build/resolvers.cjs +13 -8
- package/build/resolvers.cjs.map +2 -2
- package/build/selectors.cjs +7 -0
- package/build/selectors.cjs.map +2 -2
- package/build/utils/crdt-blocks.cjs +12 -2
- package/build/utils/crdt-blocks.cjs.map +2 -2
- package/build/utils/crdt.cjs +2 -1
- package/build/utils/crdt.cjs.map +2 -2
- package/build/utils/index.cjs +3 -0
- package/build/utils/index.cjs.map +2 -2
- package/build/utils/save-crdt-doc.cjs +75 -0
- package/build/utils/save-crdt-doc.cjs.map +7 -0
- package/build-module/awareness/block-lookup.mjs +13 -26
- package/build-module/awareness/block-lookup.mjs.map +2 -2
- package/build-module/awareness/post-editor-awareness.mjs +4 -3
- package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
- package/build-module/entities.mjs +4 -2
- package/build-module/entities.mjs.map +2 -2
- package/build-module/hooks/use-post-editor-awareness-state.mjs +9 -3
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/private-actions.mjs +7 -0
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/private-selectors.mjs.map +2 -2
- package/build-module/reducer.mjs +12 -0
- package/build-module/reducer.mjs.map +2 -2
- package/build-module/resolvers.mjs +15 -9
- package/build-module/resolvers.mjs.map +2 -2
- package/build-module/selectors.mjs +7 -0
- package/build-module/selectors.mjs.map +2 -2
- package/build-module/utils/crdt-blocks.mjs +12 -2
- package/build-module/utils/crdt-blocks.mjs.map +2 -2
- package/build-module/utils/crdt.mjs +2 -1
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-module/utils/index.mjs +2 -0
- package/build-module/utils/index.mjs.map +2 -2
- package/build-module/utils/save-crdt-doc.mjs +40 -0
- package/build-module/utils/save-crdt-doc.mjs.map +7 -0
- package/build-types/awareness/block-lookup.d.ts +27 -7
- package/build-types/awareness/block-lookup.d.ts.map +1 -1
- package/build-types/awareness/post-editor-awareness.d.ts +3 -1
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/hooks/use-post-editor-awareness-state.d.ts.map +1 -1
- package/build-types/private-actions.d.ts +15 -0
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/private-selectors.d.ts +0 -12
- package/build-types/private-selectors.d.ts.map +1 -1
- package/build-types/reducer.d.ts +15 -0
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/selectors.d.ts +4 -0
- package/build-types/selectors.d.ts.map +1 -1
- package/build-types/utils/crdt-blocks.d.ts +5 -1
- package/build-types/utils/crdt-blocks.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/build-types/utils/index.d.ts +1 -0
- package/build-types/utils/index.d.ts.map +1 -1
- package/build-types/utils/on-sub-key.d.ts +4 -0
- package/build-types/utils/on-sub-key.d.ts.map +1 -0
- package/build-types/utils/save-crdt-doc.d.ts +8 -0
- package/build-types/utils/save-crdt-doc.d.ts.map +1 -0
- package/package.json +24 -22
- package/src/awareness/block-lookup.ts +21 -62
- package/src/awareness/post-editor-awareness.ts +8 -3
- package/src/awareness/test/block-lookup.ts +98 -94
- package/src/awareness/test/post-editor-awareness.ts +177 -180
- package/src/entities.js +9 -3
- package/src/hooks/test/use-post-editor-awareness-state.ts +10 -2
- package/src/hooks/use-post-editor-awareness-state.ts +20 -7
- package/src/private-actions.js +18 -0
- package/src/private-selectors.ts +0 -12
- package/src/reducer.js +17 -0
- package/src/resolvers.js +20 -13
- package/src/selectors.ts +11 -0
- package/src/test/private-selectors.js +66 -0
- package/src/test/reducer.js +44 -0
- package/src/test/resolvers.js +121 -113
- package/src/test/selectors.js +48 -0
- package/src/utils/crdt-blocks.ts +27 -22
- package/src/utils/crdt.ts +2 -1
- package/src/utils/index.js +1 -0
- package/src/utils/save-crdt-doc.js +64 -0
- package/src/utils/test/crdt-blocks.ts +57 -2
- package/src/utils/test/rtc-rich-text-cursor-scope.test.js +2 -2
- package/src/utils/test/save-crdt-doc.js +185 -0
|
@@ -584,6 +584,14 @@ describe( 'PostEditorAwareness', () => {
|
|
|
584
584
|
} );
|
|
585
585
|
|
|
586
586
|
describe( 'convertSelectionStateToAbsolute', () => {
|
|
587
|
+
const defaultEditorBlocks = [
|
|
588
|
+
{
|
|
589
|
+
clientId: 'block-1',
|
|
590
|
+
name: 'core/paragraph',
|
|
591
|
+
innerBlocks: [],
|
|
592
|
+
},
|
|
593
|
+
];
|
|
594
|
+
|
|
587
595
|
test( 'should return nulls when relative position cannot be resolved', () => {
|
|
588
596
|
const awareness = new PostEditorAwareness(
|
|
589
597
|
doc,
|
|
@@ -611,8 +619,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
611
619
|
},
|
|
612
620
|
};
|
|
613
621
|
|
|
614
|
-
const result =
|
|
615
|
-
|
|
622
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
623
|
+
selection,
|
|
624
|
+
defaultEditorBlocks
|
|
625
|
+
);
|
|
616
626
|
|
|
617
627
|
// Should return nulls when the relative position's type cannot be found
|
|
618
628
|
expect( result.richTextOffset ).toBeNull();
|
|
@@ -651,8 +661,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
651
661
|
},
|
|
652
662
|
};
|
|
653
663
|
|
|
654
|
-
const result =
|
|
655
|
-
|
|
664
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
665
|
+
selection,
|
|
666
|
+
defaultEditorBlocks
|
|
667
|
+
);
|
|
656
668
|
|
|
657
669
|
expect( result.richTextOffset ).toBe( 5 );
|
|
658
670
|
expect( result.localClientId ).toBe( 'block-1' );
|
|
@@ -684,8 +696,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
684
696
|
blockPosition,
|
|
685
697
|
};
|
|
686
698
|
|
|
687
|
-
const result =
|
|
688
|
-
|
|
699
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
700
|
+
selection,
|
|
701
|
+
defaultEditorBlocks
|
|
702
|
+
);
|
|
689
703
|
|
|
690
704
|
expect( result.richTextOffset ).toBeNull();
|
|
691
705
|
expect( result.localClientId ).toBe( 'block-1' );
|
|
@@ -700,9 +714,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
700
714
|
123
|
|
701
715
|
);
|
|
702
716
|
|
|
703
|
-
const result = awareness.convertSelectionStateToAbsolute(
|
|
704
|
-
type: SelectionType.None,
|
|
705
|
-
|
|
717
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
718
|
+
{ type: SelectionType.None },
|
|
719
|
+
[]
|
|
720
|
+
);
|
|
706
721
|
|
|
707
722
|
expect( result.attributeKey ).toBeNull();
|
|
708
723
|
} );
|
|
@@ -737,8 +752,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
737
752
|
},
|
|
738
753
|
};
|
|
739
754
|
|
|
740
|
-
const result =
|
|
741
|
-
|
|
755
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
756
|
+
selection,
|
|
757
|
+
defaultEditorBlocks
|
|
758
|
+
);
|
|
742
759
|
|
|
743
760
|
expect( result.attributeKey ).toBe( 'body.0.cells.0.content' );
|
|
744
761
|
} );
|
|
@@ -905,13 +922,23 @@ describe( 'PostEditorAwareness', () => {
|
|
|
905
922
|
} ),
|
|
906
923
|
] );
|
|
907
924
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
925
|
+
const editorBlocks = [
|
|
926
|
+
{
|
|
927
|
+
clientId: 'local-0',
|
|
928
|
+
name: 'core/paragraph',
|
|
929
|
+
innerBlocks: [],
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
clientId: 'local-1',
|
|
933
|
+
name: 'core/paragraph',
|
|
934
|
+
innerBlocks: [],
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
clientId: 'local-2',
|
|
938
|
+
name: 'core/paragraph',
|
|
939
|
+
innerBlocks: [],
|
|
940
|
+
},
|
|
941
|
+
];
|
|
915
942
|
|
|
916
943
|
const awareness = new PostEditorAwareness(
|
|
917
944
|
nestedDoc,
|
|
@@ -942,8 +969,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
942
969
|
},
|
|
943
970
|
};
|
|
944
971
|
|
|
945
|
-
const result =
|
|
946
|
-
|
|
972
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
973
|
+
selection,
|
|
974
|
+
editorBlocks
|
|
975
|
+
);
|
|
947
976
|
|
|
948
977
|
expect( result.richTextOffset ).toBe( 2 );
|
|
949
978
|
expect( result.localClientId ).toBe( 'local-2' );
|
|
@@ -968,17 +997,24 @@ describe( 'PostEditorAwareness', () => {
|
|
|
968
997
|
|
|
969
998
|
const nestedDoc = createTestDocWithBlocks( [ outerColumn ] );
|
|
970
999
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1000
|
+
const editorBlocks = [
|
|
1001
|
+
{
|
|
1002
|
+
clientId: 'local-outer',
|
|
1003
|
+
name: 'core/column',
|
|
1004
|
+
innerBlocks: [
|
|
1005
|
+
{
|
|
1006
|
+
clientId: 'local-inner-0',
|
|
1007
|
+
name: 'core/paragraph',
|
|
1008
|
+
innerBlocks: [],
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
clientId: 'local-inner-1',
|
|
1012
|
+
name: 'core/paragraph',
|
|
1013
|
+
innerBlocks: [],
|
|
1014
|
+
},
|
|
1015
|
+
],
|
|
1016
|
+
},
|
|
1017
|
+
];
|
|
982
1018
|
|
|
983
1019
|
const awareness = new PostEditorAwareness(
|
|
984
1020
|
nestedDoc,
|
|
@@ -1015,8 +1051,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1015
1051
|
},
|
|
1016
1052
|
};
|
|
1017
1053
|
|
|
1018
|
-
const result =
|
|
1019
|
-
|
|
1054
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1055
|
+
selection,
|
|
1056
|
+
editorBlocks
|
|
1057
|
+
);
|
|
1020
1058
|
|
|
1021
1059
|
expect( result.richTextOffset ).toBe( 5 );
|
|
1022
1060
|
expect( result.localClientId ).toBe( 'local-inner-1' );
|
|
@@ -1032,16 +1070,19 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1032
1070
|
|
|
1033
1071
|
const nestedDoc = createTestDocWithBlocks( [ outerColumn ] );
|
|
1034
1072
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1073
|
+
const editorBlocks = [
|
|
1074
|
+
{
|
|
1075
|
+
clientId: 'local-col',
|
|
1076
|
+
name: 'core/column',
|
|
1077
|
+
innerBlocks: [
|
|
1078
|
+
{
|
|
1079
|
+
clientId: 'local-img',
|
|
1080
|
+
name: 'core/image',
|
|
1081
|
+
innerBlocks: [],
|
|
1082
|
+
},
|
|
1083
|
+
],
|
|
1084
|
+
},
|
|
1085
|
+
];
|
|
1045
1086
|
|
|
1046
1087
|
const awareness = new PostEditorAwareness(
|
|
1047
1088
|
nestedDoc,
|
|
@@ -1070,8 +1111,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1070
1111
|
blockPosition,
|
|
1071
1112
|
};
|
|
1072
1113
|
|
|
1073
|
-
const result =
|
|
1074
|
-
|
|
1114
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1115
|
+
selection,
|
|
1116
|
+
editorBlocks
|
|
1117
|
+
);
|
|
1075
1118
|
|
|
1076
1119
|
expect( result.richTextOffset ).toBeNull();
|
|
1077
1120
|
expect( result.localClientId ).toBe( 'local-img' );
|
|
@@ -1103,29 +1146,35 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1103
1146
|
outerColumns1,
|
|
1104
1147
|
] );
|
|
1105
1148
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1149
|
+
const editorBlocks = [
|
|
1150
|
+
{
|
|
1151
|
+
clientId: 'local-outer-0',
|
|
1152
|
+
name: 'core/columns',
|
|
1153
|
+
innerBlocks: [],
|
|
1154
|
+
},
|
|
1155
|
+
{
|
|
1156
|
+
clientId: 'local-outer-1',
|
|
1157
|
+
name: 'core/columns',
|
|
1158
|
+
innerBlocks: [
|
|
1159
|
+
{
|
|
1160
|
+
clientId: 'local-mid',
|
|
1161
|
+
name: 'core/column',
|
|
1162
|
+
innerBlocks: [
|
|
1163
|
+
{
|
|
1164
|
+
clientId: 'local-deep-0',
|
|
1165
|
+
name: 'core/paragraph',
|
|
1166
|
+
innerBlocks: [],
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
clientId: 'local-deep-1',
|
|
1170
|
+
name: 'core/paragraph',
|
|
1171
|
+
innerBlocks: [],
|
|
1172
|
+
},
|
|
1173
|
+
],
|
|
1174
|
+
},
|
|
1175
|
+
],
|
|
1176
|
+
},
|
|
1177
|
+
];
|
|
1129
1178
|
|
|
1130
1179
|
const awareness = new PostEditorAwareness(
|
|
1131
1180
|
nestedDoc,
|
|
@@ -1164,8 +1213,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1164
1213
|
},
|
|
1165
1214
|
};
|
|
1166
1215
|
|
|
1167
|
-
const result =
|
|
1168
|
-
|
|
1216
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1217
|
+
selection,
|
|
1218
|
+
editorBlocks
|
|
1219
|
+
);
|
|
1169
1220
|
|
|
1170
1221
|
expect( result.richTextOffset ).toBe( 7 );
|
|
1171
1222
|
expect( result.localClientId ).toBe( 'local-deep-1' );
|
|
@@ -1175,6 +1226,14 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1175
1226
|
} );
|
|
1176
1227
|
|
|
1177
1228
|
describe( 'convertSelectionStateToAbsolute with nested rich-text attributes', () => {
|
|
1229
|
+
const editorBlocks = [
|
|
1230
|
+
{
|
|
1231
|
+
clientId: 'local-nested-attrs',
|
|
1232
|
+
name: 'test/nested-rich-text',
|
|
1233
|
+
innerBlocks: [],
|
|
1234
|
+
},
|
|
1235
|
+
];
|
|
1236
|
+
|
|
1178
1237
|
test.each( NESTED_SELECTION_SEEDS )(
|
|
1179
1238
|
'resolves fuzzed nested rich-text cursor (seed %i)',
|
|
1180
1239
|
( seed ) => {
|
|
@@ -1185,15 +1244,6 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1185
1244
|
);
|
|
1186
1245
|
const nestedDoc = createTestDocWithBlocks( [ block ] );
|
|
1187
1246
|
|
|
1188
|
-
mockBlockEditorStore( {
|
|
1189
|
-
blocks: [
|
|
1190
|
-
{
|
|
1191
|
-
clientId: 'local-nested-attrs',
|
|
1192
|
-
innerBlocks: [],
|
|
1193
|
-
},
|
|
1194
|
-
],
|
|
1195
|
-
} );
|
|
1196
|
-
|
|
1197
1247
|
const target = rng.pick( targets );
|
|
1198
1248
|
const initialOffset = rng.intBetween(
|
|
1199
1249
|
1,
|
|
@@ -1233,8 +1283,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1233
1283
|
},
|
|
1234
1284
|
};
|
|
1235
1285
|
|
|
1236
|
-
const result =
|
|
1237
|
-
|
|
1286
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1287
|
+
selection,
|
|
1288
|
+
editorBlocks
|
|
1289
|
+
);
|
|
1238
1290
|
|
|
1239
1291
|
expect( result.richTextOffset ).toBe( expectedOffset );
|
|
1240
1292
|
expect( result.localClientId ).toBe( 'local-nested-attrs' );
|
|
@@ -1244,9 +1296,8 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1244
1296
|
);
|
|
1245
1297
|
} );
|
|
1246
1298
|
|
|
1247
|
-
describe( '
|
|
1248
|
-
test( 'should resolve cursor
|
|
1249
|
-
// Yjs doc has only the post content blocks (no template wrapper)
|
|
1299
|
+
describe( 'post content blocks resolution', () => {
|
|
1300
|
+
test( 'should resolve cursor with post content blocks', () => {
|
|
1250
1301
|
const templateDoc = createTestDocWithBlocks( [
|
|
1251
1302
|
createYBlock( 'yjs-para-0', 'core/paragraph', {
|
|
1252
1303
|
textContent: 'Post paragraph 1',
|
|
@@ -1256,55 +1307,20 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1256
1307
|
} ),
|
|
1257
1308
|
] );
|
|
1258
1309
|
|
|
1259
|
-
//
|
|
1260
|
-
//
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
},
|
|
1274
|
-
{
|
|
1275
|
-
clientId: 'local-para-1',
|
|
1276
|
-
name: 'core/paragraph',
|
|
1277
|
-
innerBlocks: [],
|
|
1278
|
-
},
|
|
1279
|
-
];
|
|
1280
|
-
}
|
|
1281
|
-
// Full template tree
|
|
1282
|
-
return [
|
|
1283
|
-
{
|
|
1284
|
-
clientId: 'local-header',
|
|
1285
|
-
name: 'core/template-part',
|
|
1286
|
-
innerBlocks: [],
|
|
1287
|
-
},
|
|
1288
|
-
{
|
|
1289
|
-
clientId: 'local-group',
|
|
1290
|
-
name: 'core/group',
|
|
1291
|
-
innerBlocks: [
|
|
1292
|
-
{
|
|
1293
|
-
clientId: postContentClientId,
|
|
1294
|
-
name: 'core/post-content',
|
|
1295
|
-
innerBlocks: [], // empty because they're controlled inner blocks
|
|
1296
|
-
},
|
|
1297
|
-
],
|
|
1298
|
-
},
|
|
1299
|
-
{
|
|
1300
|
-
clientId: 'local-footer',
|
|
1301
|
-
name: 'core/template-part',
|
|
1302
|
-
innerBlocks: [],
|
|
1303
|
-
},
|
|
1304
|
-
];
|
|
1305
|
-
} );
|
|
1306
|
-
|
|
1307
|
-
mockBlockEditorStore( { getBlocks: mockGetBlocks } );
|
|
1310
|
+
// The caller provides post content blocks directly
|
|
1311
|
+
// (template detection is handled by usePostContentBlocks).
|
|
1312
|
+
const postContentBlocks = [
|
|
1313
|
+
{
|
|
1314
|
+
clientId: 'local-para-0',
|
|
1315
|
+
name: 'core/paragraph',
|
|
1316
|
+
innerBlocks: [],
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
clientId: 'local-para-1',
|
|
1320
|
+
name: 'core/paragraph',
|
|
1321
|
+
innerBlocks: [],
|
|
1322
|
+
},
|
|
1323
|
+
];
|
|
1308
1324
|
|
|
1309
1325
|
const awareness = new PostEditorAwareness(
|
|
1310
1326
|
templateDoc,
|
|
@@ -1335,55 +1351,29 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1335
1351
|
},
|
|
1336
1352
|
};
|
|
1337
1353
|
|
|
1338
|
-
const result =
|
|
1339
|
-
|
|
1354
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1355
|
+
selection,
|
|
1356
|
+
postContentBlocks
|
|
1357
|
+
);
|
|
1340
1358
|
|
|
1341
1359
|
expect( result.richTextOffset ).toBe( 4 );
|
|
1342
|
-
// Should resolve to the post-content inner block, not a template block
|
|
1343
1360
|
expect( result.localClientId ).toBe( 'local-para-1' );
|
|
1344
|
-
// Verify getBlocks was called with the post-content clientId
|
|
1345
|
-
expect( mockGetBlocks ).toHaveBeenCalledWith( postContentClientId );
|
|
1346
1361
|
|
|
1347
1362
|
templateDoc.destroy();
|
|
1348
1363
|
} );
|
|
1349
1364
|
|
|
1350
|
-
test( 'should resolve WholeBlock
|
|
1365
|
+
test( 'should resolve WholeBlock with post content blocks', () => {
|
|
1351
1366
|
const templateDoc = createTestDocWithBlocks( [
|
|
1352
1367
|
createYBlock( 'yjs-img', 'core/image' ),
|
|
1353
1368
|
] );
|
|
1354
1369
|
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
clientId: 'local-img',
|
|
1363
|
-
name: 'core/image',
|
|
1364
|
-
innerBlocks: [],
|
|
1365
|
-
},
|
|
1366
|
-
];
|
|
1367
|
-
}
|
|
1368
|
-
return [
|
|
1369
|
-
{
|
|
1370
|
-
clientId: 'local-group',
|
|
1371
|
-
name: 'core/group',
|
|
1372
|
-
innerBlocks: [
|
|
1373
|
-
{
|
|
1374
|
-
clientId: postContentClientId,
|
|
1375
|
-
name: 'core/post-content',
|
|
1376
|
-
innerBlocks: [],
|
|
1377
|
-
},
|
|
1378
|
-
],
|
|
1379
|
-
},
|
|
1380
|
-
];
|
|
1381
|
-
} );
|
|
1382
|
-
|
|
1383
|
-
mockBlockEditorStore( {
|
|
1384
|
-
getBlocks: mockGetBlocks,
|
|
1385
|
-
getBlockName: 'core/image',
|
|
1386
|
-
} );
|
|
1370
|
+
const postContentBlocks = [
|
|
1371
|
+
{
|
|
1372
|
+
clientId: 'local-img',
|
|
1373
|
+
name: 'core/image',
|
|
1374
|
+
innerBlocks: [],
|
|
1375
|
+
},
|
|
1376
|
+
];
|
|
1387
1377
|
|
|
1388
1378
|
const awareness = new PostEditorAwareness(
|
|
1389
1379
|
templateDoc,
|
|
@@ -1407,8 +1397,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1407
1397
|
blockPosition,
|
|
1408
1398
|
};
|
|
1409
1399
|
|
|
1410
|
-
const result =
|
|
1411
|
-
|
|
1400
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1401
|
+
selection,
|
|
1402
|
+
postContentBlocks
|
|
1403
|
+
);
|
|
1412
1404
|
|
|
1413
1405
|
expect( result.richTextOffset ).toBeNull();
|
|
1414
1406
|
expect( result.localClientId ).toBe( 'local-img' );
|
|
@@ -1416,17 +1408,20 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1416
1408
|
templateDoc.destroy();
|
|
1417
1409
|
} );
|
|
1418
1410
|
|
|
1419
|
-
test( 'should
|
|
1420
|
-
// Normal mode (no template) — should use root blocks directly
|
|
1411
|
+
test( 'should resolve with root blocks directly', () => {
|
|
1421
1412
|
const normalDoc = createTestDocWithBlocks( [
|
|
1422
1413
|
createYBlock( 'yjs-para', 'core/paragraph', {
|
|
1423
1414
|
textContent: 'Normal mode',
|
|
1424
1415
|
} ),
|
|
1425
1416
|
] );
|
|
1426
1417
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1418
|
+
const editorBlocks = [
|
|
1419
|
+
{
|
|
1420
|
+
clientId: 'local-para',
|
|
1421
|
+
name: 'core/paragraph',
|
|
1422
|
+
innerBlocks: [],
|
|
1423
|
+
},
|
|
1424
|
+
];
|
|
1430
1425
|
|
|
1431
1426
|
const awareness = new PostEditorAwareness(
|
|
1432
1427
|
normalDoc,
|
|
@@ -1456,8 +1451,10 @@ describe( 'PostEditorAwareness', () => {
|
|
|
1456
1451
|
},
|
|
1457
1452
|
};
|
|
1458
1453
|
|
|
1459
|
-
const result =
|
|
1460
|
-
|
|
1454
|
+
const result = awareness.convertSelectionStateToAbsolute(
|
|
1455
|
+
selection,
|
|
1456
|
+
editorBlocks
|
|
1457
|
+
);
|
|
1461
1458
|
|
|
1462
1459
|
expect( result.richTextOffset ).toBe( 3 );
|
|
1463
1460
|
expect( result.localClientId ).toBe( 'local-para' );
|
package/src/entities.js
CHANGED
|
@@ -44,7 +44,7 @@ export const rootEntitiesConfig = [
|
|
|
44
44
|
baseURL: '/',
|
|
45
45
|
baseURLParams: {
|
|
46
46
|
// Please also change the preload path when changing this.
|
|
47
|
-
// @see lib/compat/wordpress-7.
|
|
47
|
+
// @see lib/compat/wordpress-7.1/preload.php
|
|
48
48
|
_fields: [
|
|
49
49
|
'description',
|
|
50
50
|
'gmt_offset',
|
|
@@ -306,11 +306,14 @@ export const prePersistPostType = async (
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
-
// Add meta for persisted CRDT document
|
|
309
|
+
// Add meta for the persisted CRDT document during real post saves so the
|
|
310
|
+
// saved post and CRDT snapshot are committed in the same request. We don't
|
|
311
|
+
// want a post save to fail but a CRDT update to succeed or vice versa.
|
|
312
|
+
// CRDT repair uses /wp-sync/v1/save to avoid post-save side effects.
|
|
310
313
|
if ( persistedRecord ) {
|
|
311
314
|
const objectType = `postType/${ name }`;
|
|
312
315
|
const objectId = persistedRecord.id;
|
|
313
|
-
const serializedDoc =
|
|
316
|
+
const serializedDoc = getSyncManager()?.createPersistedCRDTDoc(
|
|
314
317
|
objectType,
|
|
315
318
|
objectId
|
|
316
319
|
);
|
|
@@ -406,6 +409,9 @@ async function loadPostTypeEntities() {
|
|
|
406
409
|
* @type {import('@wordpress/sync').SyncConfig}
|
|
407
410
|
*/
|
|
408
411
|
entity.syncConfig = {
|
|
412
|
+
// Save a CRDT document with this entity
|
|
413
|
+
supportsPersistence: true,
|
|
414
|
+
|
|
409
415
|
/**
|
|
410
416
|
* Apply changes from the local editor to the local CRDT document so
|
|
411
417
|
* that those changes can be synced to other peers (via the provider).
|
|
@@ -28,6 +28,14 @@ jest.mock( '../../sync', () => ( {
|
|
|
28
28
|
getSyncManager: jest.fn(),
|
|
29
29
|
} ) );
|
|
30
30
|
|
|
31
|
+
const mockPostContentBlocks = [
|
|
32
|
+
{ clientId: 'block-1', name: 'core/paragraph', innerBlocks: [] },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
jest.mock( '../../awareness/block-lookup', () => ( {
|
|
36
|
+
usePostContentBlocks: jest.fn( () => mockPostContentBlocks ),
|
|
37
|
+
} ) );
|
|
38
|
+
|
|
31
39
|
const mockAvatarUrls = {
|
|
32
40
|
'24': 'https://example.com/avatar-24.png',
|
|
33
41
|
'48': 'https://example.com/avatar-48.png',
|
|
@@ -299,7 +307,7 @@ describe( 'use-post-editor-awareness-state hooks', () => {
|
|
|
299
307
|
} );
|
|
300
308
|
} );
|
|
301
309
|
|
|
302
|
-
test( 'should call awareness.convertSelectionStateToAbsolute with selection', () => {
|
|
310
|
+
test( 'should call awareness.convertSelectionStateToAbsolute with selection and blocks', () => {
|
|
303
311
|
const mockSelection: SelectionCursor = {
|
|
304
312
|
type: SelectionType.Cursor,
|
|
305
313
|
cursorPosition: {
|
|
@@ -321,7 +329,7 @@ describe( 'use-post-editor-awareness-state hooks', () => {
|
|
|
321
329
|
|
|
322
330
|
expect(
|
|
323
331
|
mockAwareness.convertSelectionStateToAbsolute
|
|
324
|
-
).toHaveBeenCalledWith( mockSelection );
|
|
332
|
+
).toHaveBeenCalledWith( mockSelection, mockPostContentBlocks );
|
|
325
333
|
expect( position ).toEqual( {
|
|
326
334
|
richTextOffset: 10,
|
|
327
335
|
localClientId: 'block-1',
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
4
|
import { usePrevious } from '@wordpress/compose';
|
|
5
|
-
import { useEffect, useState } from '@wordpress/element';
|
|
5
|
+
import { useEffect, useState, useCallback } from '@wordpress/element';
|
|
6
6
|
import type { Y } from '@wordpress/sync';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Internal dependencies
|
|
10
10
|
*/
|
|
11
11
|
import { getSyncManager } from '../sync';
|
|
12
|
+
import { usePostContentBlocks } from '../awareness/block-lookup';
|
|
13
|
+
import type { EditorStoreBlock } from '../awareness/block-lookup';
|
|
12
14
|
import type {
|
|
13
15
|
PostEditorAwarenessState as ActiveCollaborator,
|
|
14
16
|
PostSaveEvent,
|
|
@@ -19,7 +21,10 @@ import type { PostEditorAwareness } from '../awareness/post-editor-awareness';
|
|
|
19
21
|
|
|
20
22
|
interface AwarenessState {
|
|
21
23
|
activeCollaborators: ActiveCollaborator[];
|
|
22
|
-
resolveSelection: (
|
|
24
|
+
resolveSelection: (
|
|
25
|
+
selection: SelectionState,
|
|
26
|
+
blocks: EditorStoreBlock[]
|
|
27
|
+
) => ResolvedSelection;
|
|
23
28
|
getDebugData: () => YDocDebugData;
|
|
24
29
|
isCurrentCollaboratorDisconnected: boolean;
|
|
25
30
|
}
|
|
@@ -49,8 +54,10 @@ function getAwarenessState(
|
|
|
49
54
|
|
|
50
55
|
return {
|
|
51
56
|
activeCollaborators,
|
|
52
|
-
resolveSelection: (
|
|
53
|
-
|
|
57
|
+
resolveSelection: (
|
|
58
|
+
selection: SelectionState,
|
|
59
|
+
blocks: EditorStoreBlock[]
|
|
60
|
+
) => awareness.convertSelectionStateToAbsolute( selection, blocks ),
|
|
54
61
|
getDebugData: () => awareness.getDebugData(),
|
|
55
62
|
isCurrentCollaboratorDisconnected:
|
|
56
63
|
activeCollaborators.find( ( collaborator ) => collaborator.isMe )
|
|
@@ -124,7 +131,13 @@ export function useResolvedSelection(
|
|
|
124
131
|
postId: number | null,
|
|
125
132
|
postType: string | null
|
|
126
133
|
): ( selection: SelectionState ) => ResolvedSelection {
|
|
127
|
-
|
|
134
|
+
const blocks = usePostContentBlocks();
|
|
135
|
+
const awarenessState = usePostEditorAwarenessState( postId, postType );
|
|
136
|
+
return useCallback(
|
|
137
|
+
( selection: SelectionState ) =>
|
|
138
|
+
awarenessState.resolveSelection( selection, blocks ),
|
|
139
|
+
[ blocks, awarenessState ]
|
|
140
|
+
);
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
/**
|
|
@@ -158,8 +171,8 @@ export function useIsDisconnected(
|
|
|
158
171
|
|
|
159
172
|
/**
|
|
160
173
|
* Hook that subscribes to the CRDT state map and returns the most recent
|
|
161
|
-
* save event (timestamp + client ID). The state map is
|
|
162
|
-
* `markEntityAsSaved` in `@wordpress/sync
|
|
174
|
+
* user-facing post save event (timestamp + client ID). The state map is
|
|
175
|
+
* updated by `markEntityAsSaved` in `@wordpress/sync`.
|
|
163
176
|
*
|
|
164
177
|
* @param postId The ID of the post.
|
|
165
178
|
* @param postType The type of the post.
|
package/src/private-actions.js
CHANGED
|
@@ -197,6 +197,24 @@ export function receiveViewConfig( kind, name, config ) {
|
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Returns an action object used to notify core-data that the sync undo manager
|
|
202
|
+
* state changed outside of the core-data reducer, e.g. The Yjs UndoManager
|
|
203
|
+
* captured an undo level.
|
|
204
|
+
*
|
|
205
|
+
* @param {Object} state The sync undo stack state.
|
|
206
|
+
* @param {boolean} state.hasRedo Whether there are changes to redo.
|
|
207
|
+
* @param {boolean} state.hasUndo Whether there are changes to undo.
|
|
208
|
+
*
|
|
209
|
+
* @return {Object} Action object.
|
|
210
|
+
*/
|
|
211
|
+
export function __unstableNotifySyncUndoManagerChange( state ) {
|
|
212
|
+
return {
|
|
213
|
+
type: 'SYNC_UNDO_MANAGER_CHANGE',
|
|
214
|
+
...state,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
200
218
|
/**
|
|
201
219
|
* Returns an action object used to set the sync connection status for an entity or collection.
|
|
202
220
|
*
|