@wordpress/core-data 7.41.2-next.v.202603161435.0 → 7.43.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.
Files changed (161) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/build/awareness/post-editor-awareness.cjs +12 -5
  3. package/build/awareness/post-editor-awareness.cjs.map +2 -2
  4. package/build/entities.cjs +30 -5
  5. package/build/entities.cjs.map +2 -2
  6. package/build/hooks/use-post-editor-awareness-state.cjs +1 -1
  7. package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
  8. package/build/private-actions.cjs +10 -0
  9. package/build/private-actions.cjs.map +2 -2
  10. package/build/private-selectors.cjs +20 -3
  11. package/build/private-selectors.cjs.map +2 -2
  12. package/build/queried-data/get-query-parts.cjs +8 -0
  13. package/build/queried-data/get-query-parts.cjs.map +2 -2
  14. package/build/queried-data/reducer.cjs +15 -9
  15. package/build/queried-data/reducer.cjs.map +2 -2
  16. package/build/queried-data/selectors.cjs +10 -2
  17. package/build/queried-data/selectors.cjs.map +2 -2
  18. package/build/reducer.cjs +22 -3
  19. package/build/reducer.cjs.map +2 -2
  20. package/build/resolvers.cjs +16 -8
  21. package/build/resolvers.cjs.map +2 -2
  22. package/build/selectors.cjs +16 -8
  23. package/build/selectors.cjs.map +2 -2
  24. package/build/sync.cjs +3 -0
  25. package/build/sync.cjs.map +2 -2
  26. package/build/types.cjs.map +2 -2
  27. package/build/utils/block-selection-history.cjs +1 -1
  28. package/build/utils/block-selection-history.cjs.map +2 -2
  29. package/build/utils/crdt-blocks.cjs +66 -5
  30. package/build/utils/crdt-blocks.cjs.map +2 -2
  31. package/build/utils/crdt-selection.cjs +4 -1
  32. package/build/utils/crdt-selection.cjs.map +2 -2
  33. package/build/utils/crdt-text.cjs +52 -0
  34. package/build/utils/crdt-text.cjs.map +7 -0
  35. package/build/utils/crdt-user-selections.cjs +1 -1
  36. package/build/utils/crdt-user-selections.cjs.map +2 -2
  37. package/build/utils/crdt-utils.cjs +54 -2
  38. package/build/utils/crdt-utils.cjs.map +2 -2
  39. package/build/utils/crdt.cjs +9 -23
  40. package/build/utils/crdt.cjs.map +2 -2
  41. package/build/utils/index.cjs +0 -3
  42. package/build/utils/index.cjs.map +2 -2
  43. package/build-module/awareness/post-editor-awareness.mjs +12 -5
  44. package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
  45. package/build-module/entities.mjs +30 -5
  46. package/build-module/entities.mjs.map +2 -2
  47. package/build-module/hooks/use-post-editor-awareness-state.mjs +1 -1
  48. package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
  49. package/build-module/private-actions.mjs +9 -0
  50. package/build-module/private-actions.mjs.map +2 -2
  51. package/build-module/private-selectors.mjs +19 -3
  52. package/build-module/private-selectors.mjs.map +2 -2
  53. package/build-module/queried-data/get-query-parts.mjs +8 -0
  54. package/build-module/queried-data/get-query-parts.mjs.map +2 -2
  55. package/build-module/queried-data/reducer.mjs +15 -9
  56. package/build-module/queried-data/reducer.mjs.map +2 -2
  57. package/build-module/queried-data/selectors.mjs +10 -2
  58. package/build-module/queried-data/selectors.mjs.map +2 -2
  59. package/build-module/reducer.mjs +20 -2
  60. package/build-module/reducer.mjs.map +2 -2
  61. package/build-module/resolvers.mjs +14 -7
  62. package/build-module/resolvers.mjs.map +2 -2
  63. package/build-module/selectors.mjs +16 -9
  64. package/build-module/selectors.mjs.map +2 -2
  65. package/build-module/sync.mjs +2 -0
  66. package/build-module/sync.mjs.map +2 -2
  67. package/build-module/types.mjs.map +2 -2
  68. package/build-module/utils/block-selection-history.mjs +5 -2
  69. package/build-module/utils/block-selection-history.mjs.map +2 -2
  70. package/build-module/utils/crdt-blocks.mjs +65 -5
  71. package/build-module/utils/crdt-blocks.mjs.map +2 -2
  72. package/build-module/utils/crdt-selection.mjs +8 -2
  73. package/build-module/utils/crdt-selection.mjs.map +2 -2
  74. package/build-module/utils/crdt-text.mjs +26 -0
  75. package/build-module/utils/crdt-text.mjs.map +7 -0
  76. package/build-module/utils/crdt-user-selections.mjs +2 -2
  77. package/build-module/utils/crdt-user-selections.mjs.map +2 -2
  78. package/build-module/utils/crdt-utils.mjs +51 -1
  79. package/build-module/utils/crdt-utils.mjs.map +2 -2
  80. package/build-module/utils/crdt.mjs +10 -23
  81. package/build-module/utils/crdt.mjs.map +2 -2
  82. package/build-module/utils/index.mjs +8 -10
  83. package/build-module/utils/index.mjs.map +2 -2
  84. package/build-types/awareness/post-editor-awareness.d.ts +2 -2
  85. package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
  86. package/build-types/entities.d.ts.map +1 -1
  87. package/build-types/index.d.ts.map +1 -1
  88. package/build-types/private-actions.d.ts +10 -0
  89. package/build-types/private-actions.d.ts.map +1 -1
  90. package/build-types/private-selectors.d.ts +11 -4
  91. package/build-types/private-selectors.d.ts.map +1 -1
  92. package/build-types/queried-data/get-query-parts.d.ts +13 -14
  93. package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
  94. package/build-types/queried-data/reducer.d.ts +11 -5
  95. package/build-types/queried-data/reducer.d.ts.map +1 -1
  96. package/build-types/queried-data/selectors.d.ts.map +1 -1
  97. package/build-types/reducer.d.ts +11 -0
  98. package/build-types/reducer.d.ts.map +1 -1
  99. package/build-types/resolvers.d.ts +3 -0
  100. package/build-types/resolvers.d.ts.map +1 -1
  101. package/build-types/selectors.d.ts +1 -0
  102. package/build-types/selectors.d.ts.map +1 -1
  103. package/build-types/sync.d.ts +2 -2
  104. package/build-types/sync.d.ts.map +1 -1
  105. package/build-types/types.d.ts +4 -2
  106. package/build-types/types.d.ts.map +1 -1
  107. package/build-types/utils/block-selection-history.d.ts.map +1 -1
  108. package/build-types/utils/crdt-blocks.d.ts +11 -0
  109. package/build-types/utils/crdt-blocks.d.ts.map +1 -1
  110. package/build-types/utils/crdt-selection.d.ts.map +1 -1
  111. package/build-types/utils/crdt-text.d.ts +16 -0
  112. package/build-types/utils/crdt-text.d.ts.map +1 -0
  113. package/build-types/utils/crdt-user-selections.d.ts +1 -2
  114. package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
  115. package/build-types/utils/crdt-utils.d.ts +20 -0
  116. package/build-types/utils/crdt-utils.d.ts.map +1 -1
  117. package/build-types/utils/crdt.d.ts +6 -7
  118. package/build-types/utils/crdt.d.ts.map +1 -1
  119. package/build-types/utils/index.d.ts +0 -1
  120. package/build-types/utils/test/crdt-utils.d.ts +2 -0
  121. package/build-types/utils/test/crdt-utils.d.ts.map +1 -0
  122. package/package.json +18 -18
  123. package/src/awareness/post-editor-awareness.ts +13 -6
  124. package/src/awareness/test/post-editor-awareness.ts +15 -10
  125. package/src/entities.js +36 -5
  126. package/src/hooks/test/use-post-editor-awareness-state.ts +3 -3
  127. package/src/hooks/use-post-editor-awareness-state.ts +1 -1
  128. package/src/private-actions.js +18 -0
  129. package/src/private-selectors.ts +37 -4
  130. package/src/queried-data/get-query-parts.js +14 -7
  131. package/src/queried-data/reducer.js +28 -15
  132. package/src/queried-data/selectors.js +11 -3
  133. package/src/queried-data/test/get-query-parts.js +34 -0
  134. package/src/queried-data/test/reducer.js +78 -8
  135. package/src/queried-data/test/selectors.js +171 -0
  136. package/src/reducer.js +31 -0
  137. package/src/resolvers.js +23 -7
  138. package/src/selectors.ts +20 -19
  139. package/src/sync.ts +2 -0
  140. package/src/test/entities.js +185 -1
  141. package/src/types.ts +8 -2
  142. package/src/utils/block-selection-history.ts +5 -2
  143. package/src/utils/crdt-blocks.ts +115 -5
  144. package/src/utils/crdt-selection.ts +8 -2
  145. package/src/utils/crdt-text.ts +43 -0
  146. package/src/utils/crdt-user-selections.ts +13 -13
  147. package/src/utils/crdt-utils.ts +99 -0
  148. package/src/utils/crdt.ts +18 -30
  149. package/src/utils/index.js +0 -1
  150. package/src/utils/test/crdt-blocks.ts +199 -0
  151. package/src/utils/test/crdt-user-selections.ts +5 -0
  152. package/src/utils/test/crdt-utils.ts +387 -0
  153. package/src/utils/test/crdt.ts +229 -54
  154. package/build/utils/is-raw-attribute.cjs +0 -29
  155. package/build/utils/is-raw-attribute.cjs.map +0 -7
  156. package/build-module/utils/is-raw-attribute.mjs +0 -8
  157. package/build-module/utils/is-raw-attribute.mjs.map +0 -7
  158. package/build-types/utils/is-raw-attribute.d.ts +0 -10
  159. package/build-types/utils/is-raw-attribute.d.ts.map +0 -1
  160. package/src/utils/is-raw-attribute.js +0 -11
  161. package/src/utils/test/is-raw-attribute.js +0 -22
package/src/utils/crdt.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  */
21
21
  import { BaseAwareness } from '../awareness/base-awareness';
22
22
  import {
23
+ deserializeBlockAttributes,
23
24
  mergeCrdtBlocks,
24
25
  mergeRichTextUpdate,
25
26
  type Block,
@@ -27,7 +28,6 @@ import {
27
28
  type YBlocks,
28
29
  } from './crdt-blocks';
29
30
  import { type Post } from '../entity-types/post';
30
- import { type Type } from '../entity-types';
31
31
  import { CRDT_DOC_META_PERSISTENCE_KEY, CRDT_RECORD_MAP_KEY } from '../sync';
32
32
  import type { WPSelection } from '../types';
33
33
  import {
@@ -76,27 +76,6 @@ export interface YPostRecord extends YMapRecord {
76
76
 
77
77
  export const POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE = '_crdt_document';
78
78
 
79
- // Properties that are allowed to be synced for a post.
80
- const allowedPostProperties = new Set< string >( [
81
- 'author',
82
- 'blocks',
83
- 'content',
84
- 'categories',
85
- 'comment_status',
86
- 'date',
87
- 'excerpt',
88
- 'featured_media',
89
- 'format',
90
- 'meta',
91
- 'ping_status',
92
- 'slug',
93
- 'status',
94
- 'sticky',
95
- 'tags',
96
- 'template',
97
- 'title',
98
- ] );
99
-
100
79
  // Post meta keys that should *not* be synced.
101
80
  const disallowedPostMetaKeys = new Set< string >( [
102
81
  POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
@@ -139,18 +118,18 @@ function defaultApplyChangesToCRDTDoc(
139
118
  *
140
119
  * @param {CRDTDoc} ydoc
141
120
  * @param {PostChanges} changes
142
- * @param {Type} _postType
121
+ * @param {Set<string>} syncedProperties
143
122
  * @return {void}
144
123
  */
145
124
  export function applyPostChangesToCRDTDoc(
146
125
  ydoc: CRDTDoc,
147
126
  changes: PostChanges,
148
- _postType: Type // eslint-disable-line @typescript-eslint/no-unused-vars
127
+ syncedProperties: Set< string >
149
128
  ): void {
150
129
  const ymap = getRootMap< YPostRecord >( ydoc, CRDT_RECORD_MAP_KEY );
151
130
 
152
131
  Object.keys( changes ).forEach( ( key ) => {
153
- if ( ! allowedPostProperties.has( key ) ) {
132
+ if ( ! syncedProperties.has( key ) ) {
154
133
  return;
155
134
  }
156
135
 
@@ -289,15 +268,15 @@ function defaultGetChangesFromCRDTDoc( crdtDoc: CRDTDoc ): ObjectData {
289
268
  * against the local record and determine if there are changes (edits) we want
290
269
  * to dispatch.
291
270
  *
292
- * @param {CRDTDoc} ydoc
293
- * @param {Post} editedRecord
294
- * @param {Type} _postType
271
+ * @param {CRDTDoc} ydoc
272
+ * @param {Post} editedRecord
273
+ * @param {Set<string>} syncedProperties
295
274
  * @return {Partial<PostChanges>} The changes that should be applied to the local record.
296
275
  */
297
276
  export function getPostChangesFromCRDTDoc(
298
277
  ydoc: CRDTDoc,
299
278
  editedRecord: Post,
300
- _postType: Type // eslint-disable-line @typescript-eslint/no-unused-vars
279
+ syncedProperties: Set< string >
301
280
  ): PostChanges {
302
281
  const ymap = getRootMap< YPostRecord >( ydoc, CRDT_RECORD_MAP_KEY );
303
282
 
@@ -305,7 +284,7 @@ export function getPostChangesFromCRDTDoc(
305
284
 
306
285
  const changes = Object.fromEntries(
307
286
  Object.entries( ymap.toJSON() ).filter( ( [ key, newValue ] ) => {
308
- if ( ! allowedPostProperties.has( key ) ) {
287
+ if ( ! syncedProperties.has( key ) ) {
309
288
  return false;
310
289
  }
311
290
 
@@ -404,6 +383,15 @@ export function getPostChangesFromCRDTDoc(
404
383
  } )
405
384
  );
406
385
 
386
+ // Blocks extracted from the CRDT document have rich-text attributes as
387
+ // plain strings (from Y.Text.toJSON()). Convert them back to RichTextData
388
+ // so block edit components receive the same types as locally-created blocks.
389
+ if ( changes.blocks ) {
390
+ changes.blocks = deserializeBlockAttributes(
391
+ changes.blocks as Block[]
392
+ );
393
+ }
394
+
407
395
  // Meta changes must be merged with the edited record since not all meta
408
396
  // properties are synced.
409
397
  if ( 'object' === typeof changes.meta ) {
@@ -5,7 +5,6 @@ export { default as forwardResolver } from './forward-resolver';
5
5
  export { default as onSubKey } from './on-sub-key';
6
6
  export { default as replaceAction } from './replace-action';
7
7
  export { default as withWeakMapCache } from './with-weak-map-cache';
8
- export { default as isRawAttribute } from './is-raw-attribute';
9
8
  export { default as setNestedValue } from './set-nested-value';
10
9
  export { default as getNestedValue } from './get-nested-value';
11
10
  export { default as isNumericID } from './is-numeric-id';
@@ -38,9 +38,24 @@ jest.mock( '@wordpress/blocks', () => ( {
38
38
  url: { type: 'string' },
39
39
  },
40
40
  },
41
+ {
42
+ name: 'core/table',
43
+ attributes: {
44
+ hasFixedLayout: { type: 'boolean' },
45
+ caption: { type: 'rich-text' },
46
+ head: { type: 'array' },
47
+ body: { type: 'array' },
48
+ foot: { type: 'array' },
49
+ },
50
+ },
41
51
  ],
42
52
  } ) );
43
53
 
54
+ /**
55
+ * WordPress dependencies
56
+ */
57
+ import { RichTextData } from '@wordpress/rich-text';
58
+
44
59
  /**
45
60
  * Internal dependencies
46
61
  */
@@ -52,6 +67,7 @@ import {
52
67
  type YBlocks,
53
68
  type YBlockAttributes,
54
69
  } from '../crdt-blocks';
70
+ import { getCachedRichTextData, createRichTextDataCache } from '../crdt-text';
55
71
 
56
72
  describe( 'crdt-blocks', () => {
57
73
  let doc: Y.Doc;
@@ -1089,6 +1105,137 @@ describe( 'crdt-blocks', () => {
1089
1105
  } );
1090
1106
  } );
1091
1107
 
1108
+ describe( 'table block', () => {
1109
+ it( 'preserves table cell content through CRDT round-trip', () => {
1110
+ const tableBlocks: Block[] = [
1111
+ {
1112
+ name: 'core/table',
1113
+ attributes: {
1114
+ hasFixedLayout: true,
1115
+ body: [
1116
+ {
1117
+ cells: [
1118
+ {
1119
+ content:
1120
+ RichTextData.fromPlainText( '1' ),
1121
+ tag: 'td',
1122
+ },
1123
+ {
1124
+ content:
1125
+ RichTextData.fromPlainText( '2' ),
1126
+ tag: 'td',
1127
+ },
1128
+ ],
1129
+ },
1130
+ {
1131
+ cells: [
1132
+ {
1133
+ content:
1134
+ RichTextData.fromPlainText( '3' ),
1135
+ tag: 'td',
1136
+ },
1137
+ {
1138
+ content:
1139
+ RichTextData.fromPlainText( '4' ),
1140
+ tag: 'td',
1141
+ },
1142
+ ],
1143
+ },
1144
+ ],
1145
+ },
1146
+ innerBlocks: [],
1147
+ },
1148
+ ];
1149
+
1150
+ mergeCrdtBlocks( yblocks, tableBlocks, null );
1151
+
1152
+ // Simulate a CRDT encode/decode cycle (persistence or sync).
1153
+ const encoded = Y.encodeStateAsUpdate( doc );
1154
+ const doc2 = new Y.Doc();
1155
+ Y.applyUpdate( doc2, encoded );
1156
+
1157
+ const yblocks2 = doc2.getArray< YBlock >();
1158
+ expect( yblocks2.length ).toBe( 1 );
1159
+
1160
+ const block = yblocks2.get( 0 );
1161
+ const attrs = block.get( 'attributes' ) as YBlockAttributes;
1162
+ const body = attrs.get( 'body' ) as {
1163
+ cells: { content: string; tag: string }[];
1164
+ }[];
1165
+
1166
+ expect( body ).toHaveLength( 2 );
1167
+ expect( body[ 0 ].cells[ 0 ].content ).toBe( '1' );
1168
+ expect( body[ 0 ].cells[ 1 ].content ).toBe( '2' );
1169
+ expect( body[ 1 ].cells[ 0 ].content ).toBe( '3' );
1170
+ expect( body[ 1 ].cells[ 1 ].content ).toBe( '4' );
1171
+
1172
+ doc2.destroy();
1173
+ } );
1174
+
1175
+ it( 'preserves table cell content with HTML formatting', () => {
1176
+ const tableBlocks: Block[] = [
1177
+ {
1178
+ name: 'core/table',
1179
+ attributes: {
1180
+ hasFixedLayout: true,
1181
+ head: [
1182
+ {
1183
+ cells: [
1184
+ {
1185
+ content: RichTextData.fromHTMLString(
1186
+ '<strong>Header</strong>'
1187
+ ),
1188
+ tag: 'th',
1189
+ },
1190
+ ],
1191
+ },
1192
+ ],
1193
+ body: [
1194
+ {
1195
+ cells: [
1196
+ {
1197
+ content: RichTextData.fromHTMLString(
1198
+ '<a href="https://example.com">Link</a>'
1199
+ ),
1200
+ tag: 'td',
1201
+ },
1202
+ ],
1203
+ },
1204
+ ],
1205
+ },
1206
+ innerBlocks: [],
1207
+ },
1208
+ ];
1209
+
1210
+ mergeCrdtBlocks( yblocks, tableBlocks, null );
1211
+
1212
+ // Round-trip through encode/decode.
1213
+ const encoded = Y.encodeStateAsUpdate( doc );
1214
+ const doc2 = new Y.Doc();
1215
+ Y.applyUpdate( doc2, encoded );
1216
+
1217
+ const yblocks2 = doc2.getArray< YBlock >();
1218
+ const block = yblocks2.get( 0 );
1219
+ const attrs = block.get( 'attributes' ) as YBlockAttributes;
1220
+
1221
+ const head = attrs.get( 'head' ) as {
1222
+ cells: { content: string }[];
1223
+ }[];
1224
+ expect( head[ 0 ].cells[ 0 ].content ).toBe(
1225
+ '<strong>Header</strong>'
1226
+ );
1227
+
1228
+ const body = attrs.get( 'body' ) as {
1229
+ cells: { content: string }[];
1230
+ }[];
1231
+ expect( body[ 0 ].cells[ 0 ].content ).toBe(
1232
+ '<a href="https://example.com">Link</a>'
1233
+ );
1234
+
1235
+ doc2.destroy();
1236
+ } );
1237
+ } );
1238
+
1092
1239
  describe( 'emoji handling', () => {
1093
1240
  // Emoji like 😀 (U+1F600) are surrogate pairs in UTF-16 (.length === 2).
1094
1241
  // The CRDT sync must preserve them without corruption (no U+FFFD / '�').
@@ -1435,3 +1582,55 @@ describe( 'crdt-blocks', () => {
1435
1582
  } );
1436
1583
  } );
1437
1584
  } );
1585
+
1586
+ describe( 'getCachedRichTextData', () => {
1587
+ let spy: ReturnType< typeof jest.spyOn >;
1588
+
1589
+ beforeEach( () => {
1590
+ spy = jest.spyOn( RichTextData, 'fromHTMLString' );
1591
+ } );
1592
+
1593
+ afterEach( () => {
1594
+ spy.mockRestore();
1595
+ } );
1596
+
1597
+ it( 'does not call fromHTMLString again for the same HTML string', () => {
1598
+ getCachedRichTextData( '<strong>cached-hit</strong>' );
1599
+ getCachedRichTextData( '<strong>cached-hit</strong>' );
1600
+
1601
+ expect( spy ).toHaveBeenCalledTimes( 1 );
1602
+ } );
1603
+
1604
+ it( 'calls fromHTMLString for each unique HTML string', () => {
1605
+ getCachedRichTextData( '<strong>cached-miss-a</strong>' );
1606
+ getCachedRichTextData( '<em>cached-miss-b</em>' );
1607
+
1608
+ expect( spy ).toHaveBeenCalledTimes( 2 );
1609
+ } );
1610
+
1611
+ it( 'calls fromHTMLString again for an evicted entry', () => {
1612
+ const cacheSize = 10;
1613
+ const getCachedValue = createRichTextDataCache( cacheSize );
1614
+
1615
+ const firstString = 'eviction-test-first';
1616
+
1617
+ getCachedValue( firstString );
1618
+
1619
+ for ( let i = 1; i < cacheSize; i++ ) {
1620
+ getCachedValue( `eviction-test-${ i }` );
1621
+ }
1622
+
1623
+ // This should push firstString out of the cache.
1624
+ getCachedValue( 'eviction-test-overflow' );
1625
+
1626
+ spy.mockClear();
1627
+
1628
+ // firstString was evicted, so fromHTMLString should be called again.
1629
+ getCachedValue( firstString );
1630
+ expect( spy ).toHaveBeenCalledTimes( 1 );
1631
+
1632
+ // The overflow entry is still cached, so fromHTMLString should not be called.
1633
+ getCachedValue( 'eviction-test-overflow' );
1634
+ expect( spy ).toHaveBeenCalledTimes( 1 );
1635
+ } );
1636
+ } );
@@ -16,6 +16,11 @@ import { CRDT_RECORD_MAP_KEY } from '../../sync';
16
16
 
17
17
  jest.mock( '@wordpress/data', () => ( {
18
18
  select: jest.fn(),
19
+ // Needed because @wordpress/rich-text initialises its store at import time.
20
+ combineReducers: jest.fn( () => jest.fn( () => ( {} ) ) ),
21
+ createReduxStore: jest.fn( () => ( {} ) ),
22
+ register: jest.fn(),
23
+ createSelector: ( selector: Function ) => selector,
19
24
  } ) );
20
25
 
21
26
  jest.mock( '@wordpress/block-editor', () => ( {