@wordpress/core-data 7.45.0 → 7.45.1-next.v.202605131032.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 (181) hide show
  1. package/build/actions.cjs +8 -6
  2. package/build/actions.cjs.map +2 -2
  3. package/build/awareness/post-editor-awareness.cjs +1 -1
  4. package/build/awareness/post-editor-awareness.cjs.map +2 -2
  5. package/build/resolvers.cjs +2 -1
  6. package/build/resolvers.cjs.map +2 -2
  7. package/build/types.cjs.map +2 -2
  8. package/build/utils/block-selection-history.cjs +4 -1
  9. package/build/utils/block-selection-history.cjs.map +2 -2
  10. package/build/utils/crdt-blocks.cjs +157 -89
  11. package/build/utils/crdt-blocks.cjs.map +2 -2
  12. package/build/utils/crdt-selection.cjs +1 -1
  13. package/build/utils/crdt-selection.cjs.map +2 -2
  14. package/build/utils/crdt-user-selections.cjs +4 -1
  15. package/build/utils/crdt-user-selections.cjs.map +2 -2
  16. package/build/utils/crdt-utils.cjs +18 -6
  17. package/build/utils/crdt-utils.cjs.map +2 -2
  18. package/build/utils/crdt.cjs +12 -2
  19. package/build/utils/crdt.cjs.map +2 -2
  20. package/build-module/actions.mjs +8 -6
  21. package/build-module/actions.mjs.map +2 -2
  22. package/build-module/awareness/post-editor-awareness.mjs +5 -2
  23. package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
  24. package/build-module/resolvers.mjs +2 -1
  25. package/build-module/resolvers.mjs.map +2 -2
  26. package/build-module/types.mjs.map +2 -2
  27. package/build-module/utils/block-selection-history.mjs +5 -1
  28. package/build-module/utils/block-selection-history.mjs.map +2 -2
  29. package/build-module/utils/crdt-blocks.mjs +162 -90
  30. package/build-module/utils/crdt-blocks.mjs.map +2 -2
  31. package/build-module/utils/crdt-selection.mjs +2 -1
  32. package/build-module/utils/crdt-selection.mjs.map +2 -2
  33. package/build-module/utils/crdt-user-selections.mjs +9 -2
  34. package/build-module/utils/crdt-user-selections.mjs.map +2 -2
  35. package/build-module/utils/crdt-utils.mjs +16 -6
  36. package/build-module/utils/crdt-utils.mjs.map +2 -2
  37. package/build-module/utils/crdt.mjs +13 -2
  38. package/build-module/utils/crdt.mjs.map +2 -2
  39. package/build-types/actions.d.ts +177 -64
  40. package/build-types/actions.d.ts.map +1 -1
  41. package/build-types/awareness/awareness-state.d.ts.map +1 -1
  42. package/build-types/awareness/base-awareness.d.ts +0 -3
  43. package/build-types/awareness/base-awareness.d.ts.map +1 -1
  44. package/build-types/awareness/post-editor-awareness.d.ts +1 -8
  45. package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
  46. package/build-types/awareness/typed-awareness.d.ts.map +1 -1
  47. package/build-types/batch/create-batch.d.ts +1 -1
  48. package/build-types/batch/create-batch.d.ts.map +1 -1
  49. package/build-types/batch/default-processor.d.ts.map +1 -1
  50. package/build-types/batch/index.d.ts +2 -2
  51. package/build-types/batch/index.d.ts.map +1 -1
  52. package/build-types/entities.d.ts +114 -87
  53. package/build-types/entities.d.ts.map +1 -1
  54. package/build-types/entity-context.d.ts +1 -1
  55. package/build-types/entity-context.d.ts.map +1 -1
  56. package/build-types/entity-provider.d.ts +2 -2
  57. package/build-types/entity-provider.d.ts.map +1 -1
  58. package/build-types/entity-types/attachment.d.ts.map +1 -1
  59. package/build-types/entity-types/base-entity-records.d.ts.map +1 -1
  60. package/build-types/entity-types/base.d.ts.map +1 -1
  61. package/build-types/entity-types/comment.d.ts.map +1 -1
  62. package/build-types/entity-types/font-collection.d.ts.map +1 -1
  63. package/build-types/entity-types/font-family.d.ts.map +1 -1
  64. package/build-types/entity-types/global-styles-revision.d.ts.map +1 -1
  65. package/build-types/entity-types/icon.d.ts.map +1 -1
  66. package/build-types/entity-types/menu-location.d.ts.map +1 -1
  67. package/build-types/entity-types/nav-menu-item.d.ts.map +1 -1
  68. package/build-types/entity-types/nav-menu.d.ts.map +1 -1
  69. package/build-types/entity-types/page.d.ts.map +1 -1
  70. package/build-types/entity-types/plugin.d.ts.map +1 -1
  71. package/build-types/entity-types/post-revision.d.ts.map +1 -1
  72. package/build-types/entity-types/post-status.d.ts.map +1 -1
  73. package/build-types/entity-types/post.d.ts.map +1 -1
  74. package/build-types/entity-types/settings.d.ts.map +1 -1
  75. package/build-types/entity-types/sidebar.d.ts.map +1 -1
  76. package/build-types/entity-types/taxonomy.d.ts.map +1 -1
  77. package/build-types/entity-types/term.d.ts.map +1 -1
  78. package/build-types/entity-types/theme.d.ts.map +1 -1
  79. package/build-types/entity-types/type.d.ts.map +1 -1
  80. package/build-types/entity-types/user.d.ts.map +1 -1
  81. package/build-types/entity-types/widget-type.d.ts.map +1 -1
  82. package/build-types/entity-types/widget.d.ts.map +1 -1
  83. package/build-types/entity-types/wp-template-part.d.ts.map +1 -1
  84. package/build-types/entity-types/wp-template.d.ts.map +1 -1
  85. package/build-types/fetch/__experimental-fetch-url-data.d.ts +2 -5
  86. package/build-types/fetch/__experimental-fetch-url-data.d.ts.map +1 -1
  87. package/build-types/fetch/index.d.ts +3 -3
  88. package/build-types/fetch/index.d.ts.map +1 -1
  89. package/build-types/footnotes/get-footnotes-order.d.ts.map +1 -1
  90. package/build-types/footnotes/get-rich-text-values-cached.d.ts.map +1 -1
  91. package/build-types/footnotes/index.d.ts +1 -1
  92. package/build-types/footnotes/index.d.ts.map +1 -1
  93. package/build-types/hooks/use-entity-block-editor.d.ts +1 -1
  94. package/build-types/hooks/use-entity-block-editor.d.ts.map +1 -1
  95. package/build-types/hooks/use-entity-id.d.ts.map +1 -1
  96. package/build-types/hooks/use-entity-prop.d.ts.map +1 -1
  97. package/build-types/hooks/use-resource-permissions.d.ts.map +1 -1
  98. package/build-types/index.d.ts +155 -153
  99. package/build-types/index.d.ts.map +1 -1
  100. package/build-types/locks/actions.d.ts +1 -1
  101. package/build-types/locks/actions.d.ts.map +1 -1
  102. package/build-types/locks/engine.d.ts +1 -1
  103. package/build-types/locks/engine.d.ts.map +1 -1
  104. package/build-types/locks/reducer.d.ts.map +1 -1
  105. package/build-types/locks/selectors.d.ts +2 -2
  106. package/build-types/locks/selectors.d.ts.map +1 -1
  107. package/build-types/locks/utils.d.ts +5 -5
  108. package/build-types/locks/utils.d.ts.map +1 -1
  109. package/build-types/name.d.ts +1 -1
  110. package/build-types/name.d.ts.map +1 -1
  111. package/build-types/private-actions.d.ts +45 -29
  112. package/build-types/private-actions.d.ts.map +1 -1
  113. package/build-types/private-apis.d.ts +1 -1
  114. package/build-types/private-apis.d.ts.map +1 -1
  115. package/build-types/queried-data/actions.d.ts +3 -3
  116. package/build-types/queried-data/actions.d.ts.map +1 -1
  117. package/build-types/queried-data/get-query-parts.d.ts +10 -34
  118. package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
  119. package/build-types/queried-data/index.d.ts +3 -3
  120. package/build-types/queried-data/index.d.ts.map +1 -1
  121. package/build-types/queried-data/reducer.d.ts +7 -23
  122. package/build-types/queried-data/reducer.d.ts.map +1 -1
  123. package/build-types/queried-data/selectors.d.ts +3 -3
  124. package/build-types/queried-data/selectors.d.ts.map +1 -1
  125. package/build-types/reducer.d.ts +40 -32
  126. package/build-types/reducer.d.ts.map +1 -1
  127. package/build-types/resolvers.d.ts +130 -47
  128. package/build-types/resolvers.d.ts.map +1 -1
  129. package/build-types/selectors.d.ts +1 -1
  130. package/build-types/selectors.d.ts.map +1 -1
  131. package/build-types/types.d.ts +61 -6
  132. package/build-types/types.d.ts.map +1 -1
  133. package/build-types/utils/block-selection-history.d.ts.map +1 -1
  134. package/build-types/utils/conservative-map-item.d.ts.map +1 -1
  135. package/build-types/utils/crdt-blocks.d.ts +19 -9
  136. package/build-types/utils/crdt-blocks.d.ts.map +1 -1
  137. package/build-types/utils/crdt-selection.d.ts.map +1 -1
  138. package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
  139. package/build-types/utils/crdt-utils.d.ts +35 -2
  140. package/build-types/utils/crdt-utils.d.ts.map +1 -1
  141. package/build-types/utils/crdt.d.ts.map +1 -1
  142. package/build-types/utils/forward-resolver.d.ts +2 -2
  143. package/build-types/utils/forward-resolver.d.ts.map +1 -1
  144. package/build-types/utils/get-nested-value.d.ts.map +1 -1
  145. package/build-types/utils/get-normalized-comma-separable.d.ts +1 -1
  146. package/build-types/utils/get-normalized-comma-separable.d.ts.map +1 -1
  147. package/build-types/utils/if-matching-action.d.ts +3 -3
  148. package/build-types/utils/if-matching-action.d.ts.map +1 -1
  149. package/build-types/utils/index.d.ts +12 -12
  150. package/build-types/utils/index.d.ts.map +1 -1
  151. package/build-types/utils/is-numeric-id.d.ts.map +1 -1
  152. package/build-types/utils/log-entity-deprecation.d.ts +1 -1
  153. package/build-types/utils/log-entity-deprecation.d.ts.map +1 -1
  154. package/build-types/utils/normalize-query-for-resolution.d.ts.map +1 -1
  155. package/build-types/utils/receive-intermediate-results.d.ts +1 -1
  156. package/build-types/utils/receive-intermediate-results.d.ts.map +1 -1
  157. package/build-types/utils/replace-action.d.ts +3 -3
  158. package/build-types/utils/replace-action.d.ts.map +1 -1
  159. package/build-types/utils/set-nested-value.d.ts.map +1 -1
  160. package/build-types/utils/user-permissions.d.ts +3 -3
  161. package/build-types/utils/user-permissions.d.ts.map +1 -1
  162. package/build-types/utils/with-weak-map-cache.d.ts +1 -1
  163. package/build-types/utils/with-weak-map-cache.d.ts.map +1 -1
  164. package/package.json +20 -20
  165. package/src/actions.js +7 -9
  166. package/src/awareness/post-editor-awareness.ts +5 -2
  167. package/src/resolvers.js +2 -1
  168. package/src/test/actions.js +58 -0
  169. package/src/test/resolvers.js +115 -2
  170. package/src/test/rtc-rich-text-offset-space.test.js +204 -0
  171. package/src/types.ts +63 -6
  172. package/src/utils/block-selection-history.ts +5 -1
  173. package/src/utils/crdt-blocks.ts +316 -116
  174. package/src/utils/crdt-selection.ts +2 -1
  175. package/src/utils/crdt-user-selections.ts +9 -2
  176. package/src/utils/crdt-utils.ts +53 -10
  177. package/src/utils/crdt.ts +30 -4
  178. package/src/utils/test/crdt-blocks.ts +74 -18
  179. package/src/utils/test/crdt-utils.ts +18 -2
  180. package/src/utils/test/rtc-rich-text-cursor-scope.test.js +267 -0
  181. package/src/utils/test/rtc-rich-text-offset-space.test.js +469 -0
@@ -84,6 +84,47 @@ export function isYMap< T extends YMapRecord >(
84
84
  return value instanceof Y.Map;
85
85
  }
86
86
 
87
+ declare const richTextOffsetBrand: unique symbol;
88
+ declare const htmlStringIndexBrand: unique symbol;
89
+
90
+ /**
91
+ * Branded type to prevent confusion between HTML string indices and RichText offsets.
92
+ *
93
+ * @see asRichTextOffset()
94
+ */
95
+ export type RichTextOffset = number & {
96
+ readonly [ richTextOffsetBrand ]: 'RichTextOffset';
97
+ };
98
+
99
+ /**
100
+ * Branded type to prevent confusion between HTML string indices and RichText offsets.
101
+ *
102
+ * @see asHtmlStringIndex()
103
+ */
104
+ export type HtmlStringIndex = number & {
105
+ readonly [ htmlStringIndexBrand ]: 'HtmlStringIndex';
106
+ };
107
+
108
+ /**
109
+ * Brand a number as an offset into a RichText’s text content.
110
+ *
111
+ * @param offset The rich-text offset to brand.
112
+ * @return The branded rich-text offset.
113
+ */
114
+ export function asRichTextOffset( offset: number ): RichTextOffset {
115
+ return offset as RichTextOffset;
116
+ }
117
+
118
+ /**
119
+ * Brand a number as a string index into serialized HTML.
120
+ *
121
+ * @param index The HTML string index to brand.
122
+ * @return The branded HTML string index.
123
+ */
124
+ export function asHtmlStringIndex( index: number ): HtmlStringIndex {
125
+ return index as HtmlStringIndex;
126
+ }
127
+
87
128
  /**
88
129
  * Given a block ID and a Y.Doc, find the block in the document.
89
130
  *
@@ -141,15 +182,15 @@ function pickMarker( text: string ): string | null {
141
182
  */
142
183
  export function htmlIndexToRichTextOffset(
143
184
  html: string,
144
- htmlIndex: number
145
- ): number {
185
+ htmlIndex: HtmlStringIndex
186
+ ): RichTextOffset {
146
187
  if ( ! html.includes( '<' ) && ! html.includes( '&' ) ) {
147
- return htmlIndex;
188
+ return asRichTextOffset( htmlIndex );
148
189
  }
149
190
 
150
191
  const marker = pickMarker( html );
151
192
  if ( ! marker ) {
152
- return htmlIndex;
193
+ return asRichTextOffset( htmlIndex );
153
194
  }
154
195
 
155
196
  // Insert marker and let create() do the parsing.
@@ -158,7 +199,7 @@ export function htmlIndexToRichTextOffset(
158
199
  const value = create( { html: withMarker } );
159
200
  const markerPos = value.text.indexOf( marker );
160
201
 
161
- return markerPos === -1 ? htmlIndex : markerPos;
202
+ return asRichTextOffset( markerPos === -1 ? htmlIndex : markerPos );
162
203
  }
163
204
 
164
205
  /**
@@ -172,15 +213,15 @@ export function htmlIndexToRichTextOffset(
172
213
  */
173
214
  export function richTextOffsetToHtmlIndex(
174
215
  html: string,
175
- richTextOffset: number
176
- ): number {
216
+ richTextOffset: RichTextOffset
217
+ ): HtmlStringIndex {
177
218
  if ( ! html.includes( '<' ) && ! html.includes( '&' ) ) {
178
- return richTextOffset;
219
+ return asHtmlStringIndex( richTextOffset );
179
220
  }
180
221
 
181
222
  const marker = pickMarker( html );
182
223
  if ( ! marker ) {
183
- return richTextOffset;
224
+ return asHtmlStringIndex( richTextOffset );
184
225
  }
185
226
 
186
227
  const value = create( { html } );
@@ -200,7 +241,9 @@ export function richTextOffsetToHtmlIndex(
200
241
 
201
242
  const htmlWithMarker = toHTMLString( { value: withMarker } );
202
243
  const markerIndex = htmlWithMarker.indexOf( marker );
203
- return markerIndex === -1 ? richTextOffset : markerIndex;
244
+ return asHtmlStringIndex(
245
+ markerIndex === -1 ? richTextOffset : markerIndex
246
+ );
204
247
  }
205
248
 
206
249
  function findBlockByClientIdInBlocks(
package/src/utils/crdt.ts CHANGED
@@ -21,10 +21,11 @@ import {
21
21
  */
22
22
  import { BaseAwareness } from '../awareness/base-awareness';
23
23
  import {
24
+ type Block,
24
25
  deserializeBlockAttributes,
25
26
  mergeCrdtBlocks,
27
+ type MergeCursorPosition,
26
28
  mergeRichTextUpdate,
27
- type Block,
28
29
  type YBlock,
29
30
  type YBlocks,
30
31
  } from './crdt-blocks';
@@ -37,6 +38,7 @@ import {
37
38
  updateSelectionHistory,
38
39
  } from './crdt-selection';
39
40
  import {
41
+ asRichTextOffset,
40
42
  createYMap,
41
43
  getRootMap,
42
44
  isYMap,
@@ -161,12 +163,13 @@ export function applyPostChangesToCRDTDoc(
161
163
 
162
164
  // Block changes from typing are bundled with a 'selection' update.
163
165
  // Pass the resulting cursor position to the mergeCrdtBlocks function.
164
- const cursorPosition =
165
- changes.selection?.selectionStart?.offset ?? null;
166
+ const newCursorPosition = parseCursorSelection(
167
+ changes.selection
168
+ );
166
169
 
167
170
  // Merge blocks does not need `setValue` because it is operating on a
168
171
  // Yjs type that is already in the Y.Doc.
169
- mergeCrdtBlocks( currentBlocks, newValue, cursorPosition );
172
+ mergeCrdtBlocks( currentBlocks, newValue, newCursorPosition );
170
173
  break;
171
174
  }
172
175
 
@@ -260,6 +263,29 @@ export function applyPostChangesToCRDTDoc(
260
263
  }
261
264
  }
262
265
 
266
+ /**
267
+ * Only returns a selection object if it describes a selection within a block, with
268
+ * a cursor inside a RichText field associated with one of that block’s attributes.
269
+ *
270
+ * @param selection Selection object which might represent a selection within a block,
271
+ * within a RichText field associated with a particular attribute of
272
+ * that block, or none at all.
273
+ */
274
+ function parseCursorSelection( selection?: WPSelection ): MergeCursorPosition {
275
+ const selectionStart = selection?.selectionStart;
276
+
277
+ return selectionStart?.clientId &&
278
+ selectionStart.attributeKey &&
279
+ 'number' === typeof selectionStart.offset &&
280
+ Number.isInteger( selectionStart.offset )
281
+ ? {
282
+ attributeKey: selectionStart.attributeKey,
283
+ clientId: selectionStart.clientId,
284
+ offset: asRichTextOffset( selectionStart.offset ),
285
+ }
286
+ : null;
287
+ }
288
+
263
289
  function defaultGetChangesFromCRDTDoc( crdtDoc: CRDTDoc ): ObjectData {
264
290
  return getRootMap( crdtDoc, CRDT_RECORD_MAP_KEY ).toJSON();
265
291
  }
@@ -119,6 +119,16 @@ import {
119
119
  type YBlockAttributes,
120
120
  } from '../crdt-blocks';
121
121
  import { getCachedRichTextData, createRichTextDataCache } from '../crdt-text';
122
+ import { asHtmlStringIndex, asRichTextOffset } from '../crdt-utils';
123
+ import { type WPBlockSelection } from '../../types';
124
+
125
+ function createCursorSelection( offset: number ): WPBlockSelection {
126
+ return {
127
+ attributeKey: 'content',
128
+ clientId: 'block-1',
129
+ offset: asRichTextOffset( offset ),
130
+ };
131
+ }
122
132
 
123
133
  describe( 'crdt-blocks', () => {
124
134
  let doc: Y.Doc;
@@ -1006,6 +1016,7 @@ describe( 'crdt-blocks', () => {
1006
1016
  name: 'core/paragraph',
1007
1017
  attributes: { content: 'Hello World' },
1008
1018
  innerBlocks: [],
1019
+ clientId: 'block-1',
1009
1020
  },
1010
1021
  ];
1011
1022
 
@@ -1016,10 +1027,15 @@ describe( 'crdt-blocks', () => {
1016
1027
  name: 'core/paragraph',
1017
1028
  attributes: { content: 'XHello World' },
1018
1029
  innerBlocks: [],
1030
+ clientId: 'block-1',
1019
1031
  },
1020
1032
  ];
1021
1033
 
1022
- mergeCrdtBlocks( yblocks, updatedBlocks, 0 );
1034
+ mergeCrdtBlocks(
1035
+ yblocks,
1036
+ updatedBlocks,
1037
+ createCursorSelection( 0 )
1038
+ );
1023
1039
 
1024
1040
  const block = yblocks.get( 0 );
1025
1041
  const content = (
@@ -1034,6 +1050,7 @@ describe( 'crdt-blocks', () => {
1034
1050
  name: 'core/paragraph',
1035
1051
  attributes: { content: 'Hello World' },
1036
1052
  innerBlocks: [],
1053
+ clientId: 'block-1',
1037
1054
  },
1038
1055
  ];
1039
1056
 
@@ -1044,10 +1061,15 @@ describe( 'crdt-blocks', () => {
1044
1061
  name: 'core/paragraph',
1045
1062
  attributes: { content: 'Hello World!' },
1046
1063
  innerBlocks: [],
1064
+ clientId: 'block-1',
1047
1065
  },
1048
1066
  ];
1049
1067
 
1050
- mergeCrdtBlocks( yblocks, updatedBlocks, 11 );
1068
+ mergeCrdtBlocks(
1069
+ yblocks,
1070
+ updatedBlocks,
1071
+ createCursorSelection( 11 )
1072
+ );
1051
1073
 
1052
1074
  const block = yblocks.get( 0 );
1053
1075
  const content = (
@@ -1062,6 +1084,7 @@ describe( 'crdt-blocks', () => {
1062
1084
  name: 'core/paragraph',
1063
1085
  attributes: { content: 'Hello' },
1064
1086
  innerBlocks: [],
1087
+ clientId: 'block-1',
1065
1088
  },
1066
1089
  ];
1067
1090
 
@@ -1072,10 +1095,15 @@ describe( 'crdt-blocks', () => {
1072
1095
  name: 'core/paragraph',
1073
1096
  attributes: { content: 'Hello World' },
1074
1097
  innerBlocks: [],
1098
+ clientId: 'block-1',
1075
1099
  },
1076
1100
  ];
1077
1101
 
1078
- mergeCrdtBlocks( yblocks, updatedBlocks, 999 );
1102
+ mergeCrdtBlocks(
1103
+ yblocks,
1104
+ updatedBlocks,
1105
+ createCursorSelection( 999 )
1106
+ );
1079
1107
 
1080
1108
  const block = yblocks.get( 0 );
1081
1109
  const content = (
@@ -2602,7 +2630,11 @@ describe( 'crdt-blocks', () => {
2602
2630
  ];
2603
2631
 
2604
2632
  // Cursor after 'Hello 😀' = 6 + 2 = 8
2605
- mergeCrdtBlocks( yblocks, updatedBlocks, 8 );
2633
+ mergeCrdtBlocks(
2634
+ yblocks,
2635
+ updatedBlocks,
2636
+ createCursorSelection( 8 )
2637
+ );
2606
2638
 
2607
2639
  const block = yblocks.get( 0 );
2608
2640
  const content = (
@@ -2633,7 +2665,11 @@ describe( 'crdt-blocks', () => {
2633
2665
  ];
2634
2666
 
2635
2667
  // Cursor at position 6 (after 'Hello ', emoji was deleted)
2636
- mergeCrdtBlocks( yblocks, updatedBlocks, 6 );
2668
+ mergeCrdtBlocks(
2669
+ yblocks,
2670
+ updatedBlocks,
2671
+ createCursorSelection( 6 )
2672
+ );
2637
2673
 
2638
2674
  const block = yblocks.get( 0 );
2639
2675
  const content = (
@@ -2664,7 +2700,11 @@ describe( 'crdt-blocks', () => {
2664
2700
  ];
2665
2701
 
2666
2702
  // Cursor after 'a😀x' = 1 + 2 + 1 = 4
2667
- mergeCrdtBlocks( yblocks, updatedBlocks, 4 );
2703
+ mergeCrdtBlocks(
2704
+ yblocks,
2705
+ updatedBlocks,
2706
+ createCursorSelection( 4 )
2707
+ );
2668
2708
 
2669
2709
  const block = yblocks.get( 0 );
2670
2710
  const content = (
@@ -2696,7 +2736,11 @@ describe( 'crdt-blocks', () => {
2696
2736
  ];
2697
2737
 
2698
2738
  // Cursor after '😀 hello ' = 2 + 7 = 9
2699
- mergeCrdtBlocks( yblocks, updatedBlocks, 9 );
2739
+ mergeCrdtBlocks(
2740
+ yblocks,
2741
+ updatedBlocks,
2742
+ createCursorSelection( 9 )
2743
+ );
2700
2744
 
2701
2745
  const block = yblocks.get( 0 );
2702
2746
  const content = (
@@ -2729,7 +2773,7 @@ describe( 'crdt-blocks', () => {
2729
2773
  const yText = doc.getText( 'test' );
2730
2774
  yText.insert( 0, 'a😀b' );
2731
2775
 
2732
- mergeRichTextUpdate( yText, 'a😀c', 4 );
2776
+ mergeRichTextUpdate( yText, 'a😀c', asHtmlStringIndex( 4 ) );
2733
2777
 
2734
2778
  expect( yText.toString() ).toBe( 'a😀c' );
2735
2779
  } );
@@ -2738,7 +2782,7 @@ describe( 'crdt-blocks', () => {
2738
2782
  const yText = doc.getText( 'test' );
2739
2783
  yText.insert( 0, 'ab' );
2740
2784
 
2741
- mergeRichTextUpdate( yText, 'a😀b', 3 );
2785
+ mergeRichTextUpdate( yText, 'a😀b', asHtmlStringIndex( 3 ) );
2742
2786
 
2743
2787
  expect( yText.toString() ).toBe( 'a😀b' );
2744
2788
  } );
@@ -2747,7 +2791,7 @@ describe( 'crdt-blocks', () => {
2747
2791
  const yText = doc.getText( 'test' );
2748
2792
  yText.insert( 0, 'a😀b' );
2749
2793
 
2750
- mergeRichTextUpdate( yText, 'ab', 1 );
2794
+ mergeRichTextUpdate( yText, 'ab', asHtmlStringIndex( 1 ) );
2751
2795
 
2752
2796
  expect( yText.toString() ).toBe( 'ab' );
2753
2797
  } );
@@ -2756,7 +2800,11 @@ describe( 'crdt-blocks', () => {
2756
2800
  const yText = doc.getText( 'test' );
2757
2801
  yText.insert( 0, 'Hello 😀 World 🎉' );
2758
2802
 
2759
- mergeRichTextUpdate( yText, 'Hello 😀 Beautiful World 🎉', 19 );
2803
+ mergeRichTextUpdate(
2804
+ yText,
2805
+ 'Hello 😀 Beautiful World 🎉',
2806
+ asHtmlStringIndex( 19 )
2807
+ );
2760
2808
 
2761
2809
  expect( yText.toString() ).toBe( 'Hello 😀 Beautiful World 🎉' );
2762
2810
  } );
@@ -2766,7 +2814,7 @@ describe( 'crdt-blocks', () => {
2766
2814
  const yText = doc.getText( 'test' );
2767
2815
  yText.insert( 0, 'a🏳️‍🌈b' );
2768
2816
 
2769
- mergeRichTextUpdate( yText, 'a🏳️‍🌈xb', 7 );
2817
+ mergeRichTextUpdate( yText, 'a🏳️‍🌈xb', asHtmlStringIndex( 7 ) );
2770
2818
 
2771
2819
  expect( yText.toString() ).toBe( 'a🏳️‍🌈xb' );
2772
2820
  } );
@@ -2776,7 +2824,7 @@ describe( 'crdt-blocks', () => {
2776
2824
  const yText = doc.getText( 'test' );
2777
2825
  yText.insert( 0, 'Hi 👋🏽' );
2778
2826
 
2779
- mergeRichTextUpdate( yText, 'Hi 👋🏽!', 6 );
2827
+ mergeRichTextUpdate( yText, 'Hi 👋🏽!', asHtmlStringIndex( 6 ) );
2780
2828
 
2781
2829
  expect( yText.toString() ).toBe( 'Hi 👋🏽!' );
2782
2830
  } );
@@ -2812,7 +2860,11 @@ describe( 'crdt-blocks', () => {
2812
2860
  ];
2813
2861
 
2814
2862
  // Cursor after '𠮷野家は美味しい' = 2+1+1+1+1+1+1+1 = 9
2815
- mergeCrdtBlocks( yblocks, updatedBlocks, 9 );
2863
+ mergeCrdtBlocks(
2864
+ yblocks,
2865
+ updatedBlocks,
2866
+ createCursorSelection( 9 )
2867
+ );
2816
2868
 
2817
2869
  const block = yblocks.get( 0 );
2818
2870
  const content = (
@@ -2843,7 +2895,11 @@ describe( 'crdt-blocks', () => {
2843
2895
  },
2844
2896
  ];
2845
2897
 
2846
- mergeCrdtBlocks( yblocks, updatedBlocks, 18 );
2898
+ mergeCrdtBlocks(
2899
+ yblocks,
2900
+ updatedBlocks,
2901
+ createCursorSelection( 18 )
2902
+ );
2847
2903
 
2848
2904
  const block = yblocks.get( 0 );
2849
2905
  const content = (
@@ -2867,7 +2923,7 @@ describe( 'crdt-blocks', () => {
2867
2923
  const yText = doc.getText( 'test' );
2868
2924
  yText.insert( 0, 'a𠮷b' );
2869
2925
 
2870
- mergeRichTextUpdate( yText, 'a𠮷xb', 4 );
2926
+ mergeRichTextUpdate( yText, 'a𠮷xb', asHtmlStringIndex( 4 ) );
2871
2927
 
2872
2928
  expect( yText.toString() ).toBe( 'a𠮷xb' );
2873
2929
  } );
@@ -2877,7 +2933,7 @@ describe( 'crdt-blocks', () => {
2877
2933
  const yText = doc.getText( 'test' );
2878
2934
  yText.insert( 0, 'a𝐀b' );
2879
2935
 
2880
- mergeRichTextUpdate( yText, 'a𝐀xb', 4 );
2936
+ mergeRichTextUpdate( yText, 'a𝐀xb', asHtmlStringIndex( 4 ) );
2881
2937
 
2882
2938
  expect( yText.toString() ).toBe( 'a𝐀xb' );
2883
2939
  } );
@@ -2897,7 +2953,7 @@ describe( 'crdt-blocks', () => {
2897
2953
  const yText = doc.getText( 'test' );
2898
2954
  yText.insert( 0, 'a𝄞b' );
2899
2955
 
2900
- mergeRichTextUpdate( yText, 'a𝄞xb', 4 );
2956
+ mergeRichTextUpdate( yText, 'a𝄞xb', asHtmlStringIndex( 4 ) );
2901
2957
 
2902
2958
  expect( yText.toString() ).toBe( 'a𝄞xb' );
2903
2959
  } );
@@ -7,10 +7,26 @@ import { describe, expect, it } from '@jest/globals';
7
7
  * Internal dependencies
8
8
  */
9
9
  import {
10
- htmlIndexToRichTextOffset,
11
- richTextOffsetToHtmlIndex,
10
+ asHtmlStringIndex,
11
+ asRichTextOffset,
12
+ htmlIndexToRichTextOffset as typedHtmlIndexToRichTextOffset,
13
+ richTextOffsetToHtmlIndex as typedRichTextOffsetToHtmlIndex,
12
14
  } from '../crdt-utils';
13
15
 
16
+ function htmlIndexToRichTextOffset( html: string, htmlIndex: number ) {
17
+ return typedHtmlIndexToRichTextOffset(
18
+ html,
19
+ asHtmlStringIndex( htmlIndex )
20
+ );
21
+ }
22
+
23
+ function richTextOffsetToHtmlIndex( html: string, richTextOffset: number ) {
24
+ return typedRichTextOffsetToHtmlIndex(
25
+ html,
26
+ asRichTextOffset( richTextOffset )
27
+ );
28
+ }
29
+
14
30
  describe( 'htmlIndexToRichTextOffset', () => {
15
31
  it( 'returns the index unchanged when there are no tags', () => {
16
32
  expect( htmlIndexToRichTextOffset( 'hello world', 5 ) ).toBe( 5 );