@portabletext/editor 2.21.2 → 2.21.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "2.21.2",
3
+ "version": "2.21.3",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -90,9 +90,9 @@
90
90
  "@types/react": "^19.2.2",
91
91
  "@types/react-dom": "^19.2.2",
92
92
  "@vitejs/plugin-react": "^5.0.4",
93
- "@vitest/browser": "^4.0.6",
94
- "@vitest/browser-playwright": "^4.0.6",
95
- "@vitest/coverage-istanbul": "^4.0.6",
93
+ "@vitest/browser": "^4.0.8",
94
+ "@vitest/browser-playwright": "^4.0.8",
95
+ "@vitest/coverage-istanbul": "^4.0.8",
96
96
  "babel-plugin-react-compiler": "1.0.0",
97
97
  "eslint": "^9.38.0",
98
98
  "eslint-formatter-gha": "^1.6.0",
@@ -104,7 +104,7 @@
104
104
  "typescript": "5.9.3",
105
105
  "typescript-eslint": "^8.46.1",
106
106
  "vite": "^7.1.12",
107
- "vitest": "^4.0.6",
107
+ "vitest": "^4.0.8",
108
108
  "vitest-browser-react": "^2.0.2",
109
109
  "@portabletext/sanity-bridge": "1.2.2",
110
110
  "@portabletext/test": "^1.0.0",
@@ -16,7 +16,7 @@ import {
16
16
  parsePatch,
17
17
  } from '@sanity/diff-match-patch'
18
18
  import type {Path, PortableTextBlock, PortableTextChild} from '@sanity/types'
19
- import {Element, Node, Text, Transforms, type Descendant} from 'slate'
19
+ import {Editor, Element, Node, Text, Transforms, type Descendant} from 'slate'
20
20
  import type {EditorSchema} from '../editor/editor-schema'
21
21
  import {KEY_TO_SLATE_ELEMENT} from '../editor/weakMaps'
22
22
  import type {PortableTextSlateEditor} from '../types/editor'
@@ -202,6 +202,51 @@ function setPatch(editor: PortableTextSlateEditor, patch: SetPatch) {
202
202
 
203
203
  const isTextBlock = editor.isTextBlock(block.node)
204
204
 
205
+ if (patch.path.length === 1) {
206
+ const updatedBlock = applyAll(block.node, [
207
+ {
208
+ ...patch,
209
+ path: patch.path.slice(1),
210
+ },
211
+ ])
212
+
213
+ if (editor.isTextBlock(block.node) && Element.isElement(updatedBlock)) {
214
+ Transforms.setNodes(editor, updatedBlock, {at: [block.index]})
215
+
216
+ const previousSelection = editor.selection
217
+
218
+ // Remove the previous children
219
+ for (const [_, childPath] of Editor.nodes(editor, {
220
+ at: [block.index],
221
+ reverse: true,
222
+ mode: 'lowest',
223
+ })) {
224
+ Transforms.removeNodes(editor, {at: childPath})
225
+ }
226
+
227
+ // Insert the new children
228
+ Transforms.insertNodes(editor, updatedBlock.children, {
229
+ at: [block.index, 0],
230
+ })
231
+
232
+ // Restore the selection
233
+ if (previousSelection) {
234
+ // Update the selection on the editor object
235
+ Transforms.setSelection(editor, previousSelection)
236
+ // Actively select the previous selection
237
+ Transforms.select(editor, previousSelection)
238
+ }
239
+
240
+ return true
241
+ } else {
242
+ Transforms.setNodes(editor, updatedBlock as Partial<Node>, {
243
+ at: [block.index],
244
+ })
245
+
246
+ return true
247
+ }
248
+ }
249
+
205
250
  if (isTextBlock && patch.path[1] !== 'children') {
206
251
  const updatedBlock = applyAll(block.node, [
207
252
  {
@@ -190,7 +190,7 @@ export const stepDefinitions = [
190
190
  await userEvent.type(context.locator, text)
191
191
  }),
192
192
  When(
193
- '{string} is typed by Editor B',
193
+ '{string} is typed in Editor B',
194
194
  async (context: Context, text: string) => {
195
195
  await userEvent.type(context.locatorB, text)
196
196
  },
@@ -222,23 +222,40 @@ export const stepDefinitions = [
222
222
  */
223
223
  When(
224
224
  '{button} is pressed',
225
- async (_: Context, button: Parameter['button']) => {
225
+ async (context: Context, button: Parameter['button']) => {
226
+ const previousSelection = context.editor.getSnapshot().context.selection
226
227
  await userEvent.keyboard(button)
227
- await new Promise((resolve) => setTimeout(resolve, 100))
228
+
229
+ await vi.waitFor(() => {
230
+ const currentSelection = context.editor.getSnapshot().context.selection
231
+
232
+ if (currentSelection) {
233
+ expect(currentSelection).not.toBe(previousSelection)
234
+ }
235
+ })
228
236
  },
229
237
  ),
230
238
  When(
231
239
  '{button} is pressed {int} times',
232
- async (_: Context, button: Parameter['button'], times: number) => {
240
+ async (context: Context, button: Parameter['button'], times: number) => {
233
241
  for (let i = 0; i < times; i++) {
242
+ const previousSelection = context.editor.getSnapshot().context.selection
234
243
  await userEvent.keyboard(button)
235
- await new Promise((resolve) => setTimeout(resolve, 100))
244
+
245
+ await vi.waitFor(() => {
246
+ const currentSelection =
247
+ context.editor.getSnapshot().context.selection
248
+
249
+ if (currentSelection) {
250
+ expect(currentSelection).not.toBe(previousSelection)
251
+ }
252
+ })
236
253
  }
237
254
  },
238
255
  ),
239
256
  When(
240
257
  '{shortcut} is pressed',
241
- async (_: Context, shortcut: Parameter['shortcut']) => {
258
+ async (context: Context, shortcut: Parameter['shortcut']) => {
242
259
  const shortcuts: Record<Parameter['shortcut'], string> = {
243
260
  'deleteWord.backward': IS_MAC
244
261
  ? '{Alt>}{Backspace}{/Alt}'
@@ -248,8 +265,16 @@ export const stepDefinitions = [
248
265
  : '{Control>}{Delete}{/Control}',
249
266
  }
250
267
 
268
+ const previousSelection = context.editor.getSnapshot().context.selection
251
269
  await userEvent.keyboard(shortcuts[shortcut])
252
- await new Promise((resolve) => setTimeout(resolve, 100))
270
+
271
+ await vi.waitFor(() => {
272
+ const currentSelection = context.editor.getSnapshot().context.selection
273
+
274
+ if (currentSelection) {
275
+ expect(currentSelection).not.toBe(previousSelection)
276
+ }
277
+ })
253
278
  },
254
279
  ),
255
280
 
@@ -315,7 +340,7 @@ export const stepDefinitions = [
315
340
  },
316
341
  ),
317
342
  When(
318
- 'the caret is put after {string} by Editor B',
343
+ 'the caret is put after {string} in Editor B',
319
344
  async (context: Context, text: string) => {
320
345
  await vi.waitFor(() => {
321
346
  const selection = getSelectionAfterText(