@wordpress/core-data 7.39.1-next.v.202602091733.0 → 7.40.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 (124) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +41 -0
  3. package/build/actions.cjs +52 -0
  4. package/build/actions.cjs.map +2 -2
  5. package/build/awareness/base-awareness.cjs +1 -8
  6. package/build/awareness/base-awareness.cjs.map +2 -2
  7. package/build/awareness/types.cjs.map +1 -1
  8. package/build/awareness/utils.cjs +8 -51
  9. package/build/awareness/utils.cjs.map +2 -2
  10. package/build/entities.cjs +7 -1
  11. package/build/entities.cjs.map +2 -2
  12. package/build/hooks/use-entity-block-editor.cjs +13 -19
  13. package/build/hooks/use-entity-block-editor.cjs.map +2 -2
  14. package/build/index.cjs +6 -1
  15. package/build/index.cjs.map +2 -2
  16. package/build/private-actions.cjs +8 -0
  17. package/build/private-actions.cjs.map +2 -2
  18. package/build/private-apis.cjs +2 -1
  19. package/build/private-apis.cjs.map +2 -2
  20. package/build/private-selectors.cjs +5 -0
  21. package/build/private-selectors.cjs.map +2 -2
  22. package/build/reducer.cjs +31 -1
  23. package/build/reducer.cjs.map +2 -2
  24. package/build/resolvers.cjs +26 -1
  25. package/build/resolvers.cjs.map +2 -2
  26. package/build/selectors.cjs +15 -0
  27. package/build/selectors.cjs.map +2 -2
  28. package/build/utils/crdt-blocks.cjs +5 -3
  29. package/build/utils/crdt-blocks.cjs.map +2 -2
  30. package/build/utils/crdt.cjs +23 -19
  31. package/build/utils/crdt.cjs.map +2 -2
  32. package/build-module/actions.mjs +50 -0
  33. package/build-module/actions.mjs.map +2 -2
  34. package/build-module/awareness/base-awareness.mjs +1 -8
  35. package/build-module/awareness/base-awareness.mjs.map +2 -2
  36. package/build-module/awareness/utils.mjs +8 -51
  37. package/build-module/awareness/utils.mjs.map +2 -2
  38. package/build-module/entities.mjs +7 -1
  39. package/build-module/entities.mjs.map +2 -2
  40. package/build-module/hooks/use-entity-block-editor.mjs +13 -19
  41. package/build-module/hooks/use-entity-block-editor.mjs.map +2 -2
  42. package/build-module/index.mjs +3 -0
  43. package/build-module/index.mjs.map +2 -2
  44. package/build-module/private-actions.mjs +7 -0
  45. package/build-module/private-actions.mjs.map +2 -2
  46. package/build-module/private-apis.mjs +6 -2
  47. package/build-module/private-apis.mjs.map +2 -2
  48. package/build-module/private-selectors.mjs +8 -1
  49. package/build-module/private-selectors.mjs.map +2 -2
  50. package/build-module/reducer.mjs +29 -1
  51. package/build-module/reducer.mjs.map +2 -2
  52. package/build-module/resolvers.mjs +25 -1
  53. package/build-module/resolvers.mjs.map +2 -2
  54. package/build-module/selectors.mjs +14 -0
  55. package/build-module/selectors.mjs.map +2 -2
  56. package/build-module/utils/crdt-blocks.mjs +3 -2
  57. package/build-module/utils/crdt-blocks.mjs.map +2 -2
  58. package/build-module/utils/crdt.mjs +25 -20
  59. package/build-module/utils/crdt.mjs.map +2 -2
  60. package/build-types/actions.d.ts +12 -0
  61. package/build-types/actions.d.ts.map +1 -1
  62. package/build-types/awareness/base-awareness.d.ts.map +1 -1
  63. package/build-types/awareness/test/awareness-state.d.ts +2 -0
  64. package/build-types/awareness/test/awareness-state.d.ts.map +1 -0
  65. package/build-types/awareness/test/base-awareness.d.ts +2 -0
  66. package/build-types/awareness/test/base-awareness.d.ts.map +1 -0
  67. package/build-types/awareness/test/post-editor-awareness.d.ts +2 -0
  68. package/build-types/awareness/test/post-editor-awareness.d.ts.map +1 -0
  69. package/build-types/awareness/test/typed-awareness.d.ts +2 -0
  70. package/build-types/awareness/test/typed-awareness.d.ts.map +1 -0
  71. package/build-types/awareness/test/utils.d.ts +2 -0
  72. package/build-types/awareness/test/utils.d.ts.map +1 -0
  73. package/build-types/awareness/types.d.ts +0 -1
  74. package/build-types/awareness/types.d.ts.map +1 -1
  75. package/build-types/awareness/utils.d.ts +2 -3
  76. package/build-types/awareness/utils.d.ts.map +1 -1
  77. package/build-types/entities.d.ts.map +1 -1
  78. package/build-types/hooks/test/use-post-editor-awareness-state.d.ts +2 -0
  79. package/build-types/hooks/test/use-post-editor-awareness-state.d.ts.map +1 -0
  80. package/build-types/hooks/use-entity-block-editor.d.ts.map +1 -1
  81. package/build-types/index.d.ts +5 -0
  82. package/build-types/index.d.ts.map +1 -1
  83. package/build-types/private-actions.d.ts +8 -0
  84. package/build-types/private-actions.d.ts.map +1 -1
  85. package/build-types/private-apis.d.ts.map +1 -1
  86. package/build-types/private-selectors.d.ts +8 -1
  87. package/build-types/private-selectors.d.ts.map +1 -1
  88. package/build-types/reducer.d.ts +23 -0
  89. package/build-types/reducer.d.ts.map +1 -1
  90. package/build-types/resolvers.d.ts +3 -0
  91. package/build-types/resolvers.d.ts.map +1 -1
  92. package/build-types/selectors.d.ts +17 -0
  93. package/build-types/selectors.d.ts.map +1 -1
  94. package/build-types/utils/crdt-blocks.d.ts +9 -0
  95. package/build-types/utils/crdt-blocks.d.ts.map +1 -1
  96. package/build-types/utils/crdt.d.ts +6 -4
  97. package/build-types/utils/crdt.d.ts.map +1 -1
  98. package/package.json +18 -18
  99. package/src/actions.js +78 -0
  100. package/src/awareness/base-awareness.ts +1 -14
  101. package/src/awareness/test/awareness-state.ts +417 -0
  102. package/src/awareness/test/base-awareness.ts +321 -0
  103. package/src/awareness/test/post-editor-awareness.ts +561 -0
  104. package/src/awareness/test/typed-awareness.ts +148 -0
  105. package/src/awareness/test/utils.ts +305 -0
  106. package/src/awareness/types.ts +0 -1
  107. package/src/awareness/utils.ts +8 -82
  108. package/src/entities.js +7 -1
  109. package/src/hooks/test/use-post-editor-awareness-state.ts +477 -0
  110. package/src/hooks/use-entity-block-editor.js +15 -21
  111. package/src/index.js +7 -0
  112. package/src/private-actions.js +14 -0
  113. package/src/private-apis.js +5 -1
  114. package/src/private-selectors.ts +16 -1
  115. package/src/reducer.js +45 -0
  116. package/src/resolvers.js +31 -2
  117. package/src/selectors.ts +41 -0
  118. package/src/test/actions.js +79 -0
  119. package/src/test/entity-provider.js +74 -0
  120. package/src/test/resolvers.js +2 -0
  121. package/src/test/store.js +30 -0
  122. package/src/utils/crdt-blocks.ts +2 -2
  123. package/src/utils/crdt.ts +44 -29
  124. package/src/utils/test/crdt.ts +212 -7
@@ -53,7 +53,9 @@ describe( 'crdt', () => {
53
53
 
54
54
  applyPostChangesToCRDTDoc( doc, changes, mockPostType );
55
55
 
56
- expect( map.get( 'title' ) ).toBe( 'New Title' );
56
+ const title = map.get( 'title' );
57
+ expect( title ).toBeInstanceOf( Y.Text );
58
+ expect( title?.toString() ).toBe( 'New Title' );
57
59
  } );
58
60
 
59
61
  it( 'does not sync disallowed properties', () => {
@@ -65,7 +67,7 @@ describe( 'crdt', () => {
65
67
  applyPostChangesToCRDTDoc( doc, changes, mockPostType );
66
68
 
67
69
  expect( map.has( 'unsyncedProperty' ) ).toBe( false );
68
- expect( map.get( 'title' ) ).toBe( 'New Title' );
70
+ expect( map.get( 'title' )?.toString() ).toBe( 'New Title' );
69
71
  } );
70
72
 
71
73
  it( 'does not sync function values', () => {
@@ -85,7 +87,9 @@ describe( 'crdt', () => {
85
87
 
86
88
  applyPostChangesToCRDTDoc( doc, changes, mockPostType );
87
89
 
88
- expect( map.get( 'title' ) ).toBe( 'Raw Title' );
90
+ const title = map.get( 'title' );
91
+ expect( title ).toBeInstanceOf( Y.Text );
92
+ expect( title?.toString() ).toBe( 'Raw Title' );
89
93
  } );
90
94
 
91
95
  it( 'skips "Auto Draft" template title when no current value exists', () => {
@@ -95,7 +99,31 @@ describe( 'crdt', () => {
95
99
 
96
100
  applyPostChangesToCRDTDoc( doc, changes, mockPostType );
97
101
 
98
- expect( map.get( 'title' ) ).toBe( '' );
102
+ const title = map.get( 'title' );
103
+ expect( title ).toBeInstanceOf( Y.Text );
104
+ expect( title?.toString() ).toBe( '' );
105
+ } );
106
+
107
+ it( 'skips "Auto Draft" template title when current value is empty Y.Text', () => {
108
+ // First set an empty title (simulates a prior sync that cleared it).
109
+ applyPostChangesToCRDTDoc(
110
+ doc,
111
+ { title: '' } as PostChanges,
112
+ mockPostType
113
+ );
114
+
115
+ const title = map.get( 'title' );
116
+ expect( title ).toBeInstanceOf( Y.Text );
117
+ expect( title?.toString() ).toBe( '' );
118
+
119
+ // Now sync "Auto Draft" — should still be suppressed.
120
+ applyPostChangesToCRDTDoc(
121
+ doc,
122
+ { title: 'Auto Draft' } as PostChanges,
123
+ mockPostType
124
+ );
125
+
126
+ expect( map.get( 'title' )?.toString() ).toBe( '' );
99
127
  } );
100
128
 
101
129
  it( 'handles excerpt with RenderedText format', () => {
@@ -109,7 +137,9 @@ describe( 'crdt', () => {
109
137
 
110
138
  applyPostChangesToCRDTDoc( doc, changes, mockPostType );
111
139
 
112
- expect( map.get( 'excerpt' ) ).toBe( 'Raw excerpt' );
140
+ const excerpt = map.get( 'excerpt' );
141
+ expect( excerpt ).toBeInstanceOf( Y.Text );
142
+ expect( excerpt?.toString() ).toBe( 'Raw excerpt' );
113
143
  } );
114
144
 
115
145
  it( 'does not sync empty slug', () => {
@@ -163,6 +193,110 @@ describe( 'crdt', () => {
163
193
  expect( blocks ).toBeInstanceOf( Y.Array );
164
194
  } );
165
195
 
196
+ it( 'sets blocks to undefined when blocks value is undefined', () => {
197
+ // First, set some blocks.
198
+ map.set( 'blocks', new Y.Array< YBlock >() );
199
+
200
+ const changes = {
201
+ blocks: undefined,
202
+ };
203
+
204
+ applyPostChangesToCRDTDoc( doc, changes, mockPostType );
205
+
206
+ // The key should still exist, but the value should be undefined.
207
+ expect( map.has( 'blocks' ) ).toBe( true );
208
+ expect( map.get( 'blocks' ) ).toBeUndefined();
209
+ } );
210
+
211
+ it( 'syncs content as Y.Text', () => {
212
+ const changes = {
213
+ content: 'Hello, world!',
214
+ } as PostChanges;
215
+
216
+ applyPostChangesToCRDTDoc( doc, changes, mockPostType );
217
+
218
+ const content = map.get( 'content' );
219
+ expect( content ).toBeInstanceOf( Y.Text );
220
+ expect( content?.toString() ).toBe( 'Hello, world!' );
221
+ } );
222
+
223
+ it( 'syncs content with RenderedText format', () => {
224
+ const changes = {
225
+ content: {
226
+ raw: '<!-- wp:paragraph --><p>Hello</p><!-- /wp:paragraph -->',
227
+ rendered: '<p>Hello</p>',
228
+ },
229
+ } as PostChanges;
230
+
231
+ applyPostChangesToCRDTDoc( doc, changes, mockPostType );
232
+
233
+ const content = map.get( 'content' );
234
+ expect( content ).toBeInstanceOf( Y.Text );
235
+ expect( content?.toString() ).toBe(
236
+ '<!-- wp:paragraph --><p>Hello</p><!-- /wp:paragraph -->'
237
+ );
238
+ } );
239
+
240
+ it( 'updates existing Y.Text title in place via mergeRichTextUpdate', () => {
241
+ // First apply to create the Y.Text.
242
+ applyPostChangesToCRDTDoc(
243
+ doc,
244
+ { title: 'Old Title' } as PostChanges,
245
+ mockPostType
246
+ );
247
+ const titleRef = map.get( 'title' );
248
+
249
+ // Apply again — should update in place, not replace.
250
+ applyPostChangesToCRDTDoc(
251
+ doc,
252
+ { title: 'New Title' } as PostChanges,
253
+ mockPostType
254
+ );
255
+
256
+ expect( map.get( 'title' ) ).toBe( titleRef );
257
+ expect( map.get( 'title' )?.toString() ).toBe( 'New Title' );
258
+ } );
259
+
260
+ it( 'updates existing Y.Text content in place via mergeRichTextUpdate', () => {
261
+ // First apply to create the Y.Text.
262
+ applyPostChangesToCRDTDoc(
263
+ doc,
264
+ { content: 'Old content' } as PostChanges,
265
+ mockPostType
266
+ );
267
+ const contentRef = map.get( 'content' );
268
+
269
+ // Apply again — should update in place, not replace.
270
+ applyPostChangesToCRDTDoc(
271
+ doc,
272
+ { content: 'New content' } as PostChanges,
273
+ mockPostType
274
+ );
275
+
276
+ expect( map.get( 'content' ) ).toBe( contentRef );
277
+ expect( map.get( 'content' )?.toString() ).toBe( 'New content' );
278
+ } );
279
+
280
+ it( 'updates existing Y.Text excerpt in place via mergeRichTextUpdate', () => {
281
+ // First apply to create the Y.Text.
282
+ applyPostChangesToCRDTDoc(
283
+ doc,
284
+ { excerpt: 'Old excerpt' } as PostChanges,
285
+ mockPostType
286
+ );
287
+ const excerptRef = map.get( 'excerpt' );
288
+
289
+ // Apply again — should update in place, not replace.
290
+ applyPostChangesToCRDTDoc(
291
+ doc,
292
+ { excerpt: 'New excerpt' } as PostChanges,
293
+ mockPostType
294
+ );
295
+
296
+ expect( map.get( 'excerpt' ) ).toBe( excerptRef );
297
+ expect( map.get( 'excerpt' )?.toString() ).toBe( 'New excerpt' );
298
+ } );
299
+
166
300
  it( 'syncs meta fields', () => {
167
301
  const changes = {
168
302
  meta: {
@@ -226,7 +360,7 @@ describe( 'crdt', () => {
226
360
 
227
361
  beforeEach( () => {
228
362
  map = getRootMap< YPostRecord >( doc, CRDT_RECORD_MAP_KEY );
229
- map.set( 'title', 'CRDT Title' );
363
+ map.set( 'title', new Y.Text( 'CRDT Title' ) );
230
364
  map.set( 'status', 'draft' );
231
365
  map.set( 'date', '2025-01-01' );
232
366
  } );
@@ -247,7 +381,7 @@ describe( 'crdt', () => {
247
381
  } );
248
382
 
249
383
  it( 'filters out disallowed properties', () => {
250
- map.set( 'title', 'Test title' );
384
+ map.set( 'title', new Y.Text( 'Test title' ) );
251
385
  map.set( 'unsyncedProp', 'value' );
252
386
 
253
387
  const editedRecord = {} as Post;
@@ -352,6 +486,77 @@ describe( 'crdt', () => {
352
486
  expect( changes ).toHaveProperty( 'blocks' );
353
487
  } );
354
488
 
489
+ it( 'includes undefined blocks in changes', () => {
490
+ map.set( 'blocks', undefined );
491
+
492
+ const editedRecord = {
493
+ blocks: [
494
+ {
495
+ name: 'core/paragraph',
496
+ attributes: { content: 'Test' },
497
+ innerBlocks: [],
498
+ },
499
+ ],
500
+ } as unknown as Post;
501
+
502
+ const changes = getPostChangesFromCRDTDoc(
503
+ doc,
504
+ editedRecord,
505
+ mockPostType
506
+ );
507
+
508
+ expect( changes ).toHaveProperty( 'blocks' );
509
+ expect( changes.blocks ).toBeUndefined();
510
+ } );
511
+
512
+ it( 'detects content changes from string value', () => {
513
+ map.set( 'content', new Y.Text( 'New content' ) );
514
+
515
+ const editedRecord = {
516
+ content: 'Old content',
517
+ } as unknown as Post;
518
+
519
+ const changes = getPostChangesFromCRDTDoc(
520
+ doc,
521
+ editedRecord,
522
+ mockPostType
523
+ );
524
+
525
+ expect( changes.content ).toBe( 'New content' );
526
+ } );
527
+
528
+ it( 'detects content changes from RenderedText value', () => {
529
+ map.set( 'content', new Y.Text( 'New content' ) );
530
+
531
+ const editedRecord = {
532
+ content: { raw: 'Old content', rendered: 'Old content' },
533
+ } as unknown as Post;
534
+
535
+ const changes = getPostChangesFromCRDTDoc(
536
+ doc,
537
+ editedRecord,
538
+ mockPostType
539
+ );
540
+
541
+ expect( changes.content ).toBe( 'New content' );
542
+ } );
543
+
544
+ it( 'excludes content when unchanged from RenderedText value', () => {
545
+ map.set( 'content', new Y.Text( 'Same content' ) );
546
+
547
+ const editedRecord = {
548
+ content: { raw: 'Same content', rendered: 'Same content' },
549
+ } as unknown as Post;
550
+
551
+ const changes = getPostChangesFromCRDTDoc(
552
+ doc,
553
+ editedRecord,
554
+ mockPostType
555
+ );
556
+
557
+ expect( changes ).not.toHaveProperty( 'content' );
558
+ } );
559
+
355
560
  it( 'includes meta in changes', () => {
356
561
  const metaMap = createYMap();
357
562
  metaMap.set( 'public_meta', 'new value' );