@wordpress/core-data 7.40.2-next.v.202602241322.0 → 7.41.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 (100) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/actions.cjs +1 -1
  3. package/build/actions.cjs.map +2 -2
  4. package/build/awareness/types.cjs.map +1 -1
  5. package/build/entities.cjs +17 -10
  6. package/build/entities.cjs.map +2 -2
  7. package/build/hooks/use-post-editor-awareness-state.cjs +38 -0
  8. package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
  9. package/build/private-actions.cjs +7 -2
  10. package/build/private-actions.cjs.map +2 -2
  11. package/build/private-apis.cjs +4 -1
  12. package/build/private-apis.cjs.map +2 -2
  13. package/build/private-selectors.cjs +7 -2
  14. package/build/private-selectors.cjs.map +2 -2
  15. package/build/reducer.cjs +11 -1
  16. package/build/reducer.cjs.map +2 -2
  17. package/build/resolvers.cjs +15 -12
  18. package/build/resolvers.cjs.map +2 -2
  19. package/build/selectors.cjs.map +2 -2
  20. package/build/sync.cjs +5 -5
  21. package/build/sync.cjs.map +1 -1
  22. package/build/types.cjs.map +1 -1
  23. package/build/utils/crdt-blocks.cjs +50 -31
  24. package/build/utils/crdt-blocks.cjs.map +2 -2
  25. package/build/utils/crdt-selection.cjs +46 -18
  26. package/build/utils/crdt-selection.cjs.map +2 -2
  27. package/build/utils/crdt.cjs +12 -1
  28. package/build/utils/crdt.cjs.map +2 -2
  29. package/build-module/actions.mjs +1 -1
  30. package/build-module/actions.mjs.map +2 -2
  31. package/build-module/entities.mjs +19 -11
  32. package/build-module/entities.mjs.map +2 -2
  33. package/build-module/hooks/use-post-editor-awareness-state.mjs +37 -0
  34. package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
  35. package/build-module/private-actions.mjs +5 -1
  36. package/build-module/private-actions.mjs.map +2 -2
  37. package/build-module/private-apis.mjs +6 -2
  38. package/build-module/private-apis.mjs.map +2 -2
  39. package/build-module/private-selectors.mjs +5 -1
  40. package/build-module/private-selectors.mjs.map +2 -2
  41. package/build-module/reducer.mjs +10 -1
  42. package/build-module/reducer.mjs.map +2 -2
  43. package/build-module/resolvers.mjs +15 -12
  44. package/build-module/resolvers.mjs.map +2 -2
  45. package/build-module/selectors.mjs.map +2 -2
  46. package/build-module/sync.mjs +3 -3
  47. package/build-module/sync.mjs.map +1 -1
  48. package/build-module/utils/crdt-blocks.mjs +50 -31
  49. package/build-module/utils/crdt-blocks.mjs.map +2 -2
  50. package/build-module/utils/crdt-selection.mjs +45 -18
  51. package/build-module/utils/crdt-selection.mjs.map +2 -2
  52. package/build-module/utils/crdt.mjs +16 -6
  53. package/build-module/utils/crdt.mjs.map +2 -2
  54. package/build-types/awareness/types.d.ts +5 -0
  55. package/build-types/awareness/types.d.ts.map +1 -1
  56. package/build-types/entities.d.ts +1 -1
  57. package/build-types/entities.d.ts.map +1 -1
  58. package/build-types/hooks/use-post-editor-awareness-state.d.ts +10 -1
  59. package/build-types/hooks/use-post-editor-awareness-state.d.ts.map +1 -1
  60. package/build-types/index.d.ts.map +1 -1
  61. package/build-types/private-actions.d.ts +1 -0
  62. package/build-types/private-actions.d.ts.map +1 -1
  63. package/build-types/private-apis.d.ts.map +1 -1
  64. package/build-types/private-selectors.d.ts +7 -0
  65. package/build-types/private-selectors.d.ts.map +1 -1
  66. package/build-types/reducer.d.ts +15 -0
  67. package/build-types/reducer.d.ts.map +1 -1
  68. package/build-types/resolvers.d.ts.map +1 -1
  69. package/build-types/selectors.d.ts +1 -0
  70. package/build-types/selectors.d.ts.map +1 -1
  71. package/build-types/sync.d.ts +2 -2
  72. package/build-types/sync.d.ts.map +1 -1
  73. package/build-types/types.d.ts +1 -0
  74. package/build-types/types.d.ts.map +1 -1
  75. package/build-types/utils/crdt-blocks.d.ts +1 -1
  76. package/build-types/utils/crdt-blocks.d.ts.map +1 -1
  77. package/build-types/utils/crdt-selection.d.ts +10 -0
  78. package/build-types/utils/crdt-selection.d.ts.map +1 -1
  79. package/build-types/utils/crdt.d.ts +1 -0
  80. package/build-types/utils/crdt.d.ts.map +1 -1
  81. package/package.json +18 -18
  82. package/src/actions.js +2 -2
  83. package/src/awareness/types.ts +6 -0
  84. package/src/entities.js +23 -11
  85. package/src/hooks/use-post-editor-awareness-state.ts +70 -0
  86. package/src/private-actions.js +13 -0
  87. package/src/private-apis.js +4 -0
  88. package/src/private-selectors.ts +10 -0
  89. package/src/reducer.js +21 -0
  90. package/src/resolvers.js +21 -15
  91. package/src/selectors.ts +1 -0
  92. package/src/sync.ts +2 -2
  93. package/src/test/entities.js +47 -14
  94. package/src/test/resolvers.js +46 -80
  95. package/src/types.ts +1 -0
  96. package/src/utils/crdt-blocks.ts +113 -47
  97. package/src/utils/crdt-selection.ts +84 -24
  98. package/src/utils/crdt.ts +23 -7
  99. package/src/utils/test/crdt-blocks.ts +938 -0
  100. package/src/utils/test/crdt.ts +136 -10
@@ -11,17 +11,16 @@ import { describe, expect, it, jest, beforeEach } from '@jest/globals';
11
11
  /**
12
12
  * Internal dependencies
13
13
  */
14
- import {
15
- CRDT_RECORD_MAP_KEY,
16
- WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
17
- } from '../../sync';
14
+ import { CRDT_RECORD_MAP_KEY } from '../../sync';
18
15
  import {
19
16
  applyPostChangesToCRDTDoc,
20
17
  getPostChangesFromCRDTDoc,
18
+ POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
21
19
  type PostChanges,
22
20
  type YPostRecord,
23
21
  } from '../crdt';
24
- import type { YBlock, YBlocks } from '../crdt-blocks';
22
+ import type { YBlock, YBlockRecord, YBlocks } from '../crdt-blocks';
23
+ import { updateSelectionHistory } from '../crdt-selection';
25
24
  import { createYMap, getRootMap, type YMapWrap } from '../crdt-utils';
26
25
  import type { Post, Type } from '../../entity-types';
27
26
 
@@ -604,10 +603,7 @@ describe( 'crdt', () => {
604
603
  it( 'excludes disallowed meta keys in changes', () => {
605
604
  const metaMap = createYMap();
606
605
  metaMap.set( 'public_meta', 'new value' );
607
- metaMap.set(
608
- WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
609
- 'exclude me'
610
- );
606
+ metaMap.set( POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE, 'exclude me' );
611
607
  map.set( 'meta', metaMap );
612
608
 
613
609
  const editedRecord = {
@@ -626,8 +622,138 @@ describe( 'crdt', () => {
626
622
  public_meta: 'new value', // from CRDT
627
623
  } );
628
624
  expect( changes.meta ).not.toHaveProperty(
629
- WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE
625
+ POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE
630
626
  );
631
627
  } );
628
+
629
+ describe( 'selection recalculation', () => {
630
+ it( 'includes recalculated selection when text is inserted before cursor', () => {
631
+ const ytext = addBlockToDoc( map, 'block-1', 'Hello world' );
632
+
633
+ // Record a selection at offset 5 (cursor between "Hello" and " world").
634
+ updateSelectionHistory( doc, {
635
+ selectionStart: {
636
+ clientId: 'block-1',
637
+ attributeKey: 'content',
638
+ offset: 5,
639
+ },
640
+ selectionEnd: {
641
+ clientId: 'block-1',
642
+ attributeKey: 'content',
643
+ offset: 5,
644
+ },
645
+ } );
646
+
647
+ // Simulate remote insertion: insert "XXX" at position 0.
648
+ ytext.insert( 0, 'XXX' );
649
+
650
+ const editedRecord = {
651
+ title: 'CRDT Title',
652
+ status: 'draft',
653
+ blocks: [],
654
+ } as unknown as Post;
655
+
656
+ const changes = getPostChangesFromCRDTDoc(
657
+ doc,
658
+ editedRecord,
659
+ mockPostType
660
+ );
661
+
662
+ expect( changes.selection ).toBeDefined();
663
+ expect( changes.selection?.selectionStart.offset ).toBe( 8 ); // 5 + 3
664
+ expect( changes.selection?.selectionStart.clientId ).toBe(
665
+ 'block-1'
666
+ );
667
+ expect( changes.selection?.selectionStart.attributeKey ).toBe(
668
+ 'content'
669
+ );
670
+ expect( changes.selection?.selectionEnd.offset ).toBe( 8 );
671
+ } );
672
+
673
+ it( 'includes recalculated selection when text is deleted before cursor', () => {
674
+ const ytext = addBlockToDoc( map, 'block-1', 'Hello world' );
675
+
676
+ // Record a selection at offset 8 (cursor between "Hello wo" and "rld").
677
+ updateSelectionHistory( doc, {
678
+ selectionStart: {
679
+ clientId: 'block-1',
680
+ attributeKey: 'content',
681
+ offset: 8,
682
+ },
683
+ selectionEnd: {
684
+ clientId: 'block-1',
685
+ attributeKey: 'content',
686
+ offset: 8,
687
+ },
688
+ } );
689
+
690
+ // Simulate remote deletion: delete "Hello" (5 chars at position 0).
691
+ ytext.delete( 0, 5 );
692
+
693
+ const editedRecord = {
694
+ title: 'CRDT Title',
695
+ status: 'draft',
696
+ blocks: [],
697
+ } as unknown as Post;
698
+
699
+ const changes = getPostChangesFromCRDTDoc(
700
+ doc,
701
+ editedRecord,
702
+ mockPostType
703
+ );
704
+
705
+ expect( changes.selection ).toBeDefined();
706
+ expect( changes.selection?.selectionStart.offset ).toBe( 3 ); // 8 - 5
707
+ } );
708
+
709
+ it( 'does not include selection when selection history is empty', () => {
710
+ addBlockToDoc( map, 'block-1', 'Hello world' );
711
+
712
+ const editedRecord = {
713
+ title: 'CRDT Title',
714
+ status: 'draft',
715
+ blocks: [],
716
+ } as unknown as Post;
717
+
718
+ const changes = getPostChangesFromCRDTDoc(
719
+ doc,
720
+ editedRecord,
721
+ mockPostType
722
+ );
723
+
724
+ expect( changes.selection ).toBeUndefined();
725
+ } );
726
+ } );
632
727
  } );
633
728
  } );
729
+
730
+ /**
731
+ * Helper to create a block with a Y.Text content attribute
732
+ * in the CRDT document.
733
+ *
734
+ * @param map
735
+ * @param clientId Block client ID.
736
+ * @param content Initial text content.
737
+ */
738
+ function addBlockToDoc(
739
+ map: YMapWrap< YPostRecord >,
740
+ clientId: string,
741
+ content: string
742
+ ): Y.Text {
743
+ let blocks = map.get( 'blocks' );
744
+ if ( ! ( blocks instanceof Y.Array ) ) {
745
+ blocks = new Y.Array< YBlock >();
746
+ map.set( 'blocks', blocks );
747
+ }
748
+
749
+ const block = createYMap< YBlockRecord >();
750
+ block.set( 'clientId', clientId );
751
+ const attrs = new Y.Map();
752
+ const ytext = new Y.Text( content );
753
+ attrs.set( 'content', ytext );
754
+ block.set( 'attributes', attrs );
755
+ block.set( 'innerBlocks', new Y.Array() );
756
+ ( blocks as YBlocks ).push( [ block ] );
757
+
758
+ return ytext;
759
+ }