@portabletext/editor 1.1.1 → 1.1.2

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 (51) hide show
  1. package/README.md +3 -0
  2. package/lib/index.d.mts +1667 -0
  3. package/lib/index.d.ts +1667 -0
  4. package/lib/index.esm.js +305 -153
  5. package/lib/index.esm.js.map +1 -1
  6. package/lib/index.js +305 -154
  7. package/lib/index.js.map +1 -1
  8. package/lib/index.mjs +305 -153
  9. package/lib/index.mjs.map +1 -1
  10. package/package.json +23 -22
  11. package/src/editor/Editable.tsx +30 -31
  12. package/src/editor/PortableTextEditor.tsx +23 -6
  13. package/src/editor/__tests__/PortableTextEditor.test.tsx +9 -9
  14. package/src/editor/__tests__/PortableTextEditorTester.tsx +2 -5
  15. package/src/editor/__tests__/RangeDecorations.test.tsx +2 -2
  16. package/src/editor/__tests__/handleClick.test.tsx +27 -7
  17. package/src/editor/__tests__/insert-block.test.tsx +4 -4
  18. package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +7 -7
  19. package/src/editor/__tests__/self-solving.test.tsx +176 -0
  20. package/src/editor/components/Leaf.tsx +28 -23
  21. package/src/editor/components/Synchronizer.tsx +60 -32
  22. package/src/editor/editor-machine.ts +195 -0
  23. package/src/editor/hooks/usePortableTextEditorSelection.tsx +11 -13
  24. package/src/editor/hooks/useSyncValue.test.tsx +9 -9
  25. package/src/editor/hooks/useSyncValue.ts +14 -13
  26. package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +1 -1
  27. package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +28 -28
  28. package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +17 -17
  29. package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +8 -8
  30. package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +5 -5
  31. package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +2 -2
  32. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +46 -46
  33. package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +22 -11
  34. package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +9 -9
  35. package/src/editor/plugins/createWithInsertData.ts +4 -8
  36. package/src/editor/plugins/createWithObjectKeys.ts +7 -0
  37. package/src/editor/plugins/createWithPatches.ts +5 -6
  38. package/src/editor/plugins/createWithPortableTextBlockStyle.ts +10 -2
  39. package/src/editor/plugins/createWithPortableTextMarkModel.ts +20 -4
  40. package/src/editor/plugins/createWithPortableTextSelections.ts +4 -5
  41. package/src/editor/plugins/createWithSchemaTypes.ts +9 -0
  42. package/src/editor/plugins/index.ts +18 -8
  43. package/src/index.ts +9 -3
  44. package/src/utils/__tests__/dmpToOperations.test.ts +1 -1
  45. package/src/utils/__tests__/operationToPatches.test.ts +61 -61
  46. package/src/utils/__tests__/patchToOperations.test.ts +39 -39
  47. package/src/utils/__tests__/ranges.test.ts +1 -1
  48. package/src/utils/__tests__/valueNormalization.test.tsx +14 -2
  49. package/src/utils/__tests__/values.test.ts +17 -17
  50. package/src/utils/validateValue.ts +0 -22
  51. package/src/editor/__tests__/utils.ts +0 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -47,29 +47,30 @@
47
47
  "is-hotkey-esm": "^1.0.0",
48
48
  "lodash": "^4.17.21",
49
49
  "slate": "0.103.0",
50
- "slate-react": "0.108.0"
50
+ "slate-react": "0.110.1",
51
+ "xstate": "^5.18.2"
51
52
  },
52
53
  "devDependencies": {
53
- "@cucumber/cucumber-expressions": "^17.1.0",
54
- "@cucumber/gherkin": "^29.0.0",
55
- "@cucumber/messages": "^26.0.0",
54
+ "@babel/preset-env": "^7.25.4",
55
+ "@babel/preset-react": "^7.24.7",
56
56
  "@jest/globals": "^29.7.0",
57
57
  "@jest/types": "^29.6.3",
58
- "@playwright/test": "1.46.1",
58
+ "@playwright/test": "1.47.2",
59
59
  "@portabletext/toolkit": "^2.0.15",
60
60
  "@sanity/block-tools": "^3.55.0",
61
61
  "@sanity/diff-match-patch": "^3.1.1",
62
- "@sanity/pkg-utils": "^6.10.10",
62
+ "@sanity/pkg-utils": "^6.11.2",
63
63
  "@sanity/schema": "^3.55.0",
64
64
  "@sanity/test": "0.0.1-alpha.1",
65
65
  "@sanity/types": "^3.55.0",
66
- "@sanity/ui": "^2.8.8",
66
+ "@sanity/ui": "^2.8.9",
67
67
  "@sanity/util": "^3.55.0",
68
68
  "@testing-library/dom": "^10.4.0",
69
- "@testing-library/react": "^16.0.0",
69
+ "@testing-library/jest-dom": "^6.5.0",
70
+ "@testing-library/react": "^16.0.1",
70
71
  "@types/debug": "^4.1.5",
71
72
  "@types/express": "^4.17.21",
72
- "@types/express-ws": "^3.0.4",
73
+ "@types/express-ws": "^3.0.5",
73
74
  "@types/lodash": "^4.17.7",
74
75
  "@types/node": "^18.19.8",
75
76
  "@types/node-ipc": "^9.2.3",
@@ -81,18 +82,19 @@
81
82
  "express": "^4.19.2",
82
83
  "express-ws": "^5.0.2",
83
84
  "jest": "^29.7.0",
84
- "jest-dev-server": "^10.1.0",
85
- "jest-environment-jsdom": "^29.7.0",
85
+ "jest-dev-server": "^10.1.1",
86
86
  "jest-environment-node": "^29.7.0",
87
+ "jsdom": "^25.0.1",
87
88
  "node-ipc": "npm:@node-ipc/compat@9.2.5",
88
89
  "react": "^18.3.1",
89
90
  "react-dom": "^18.3.1",
90
91
  "rxjs": "^7.8.1",
91
- "styled-components": "^6.1.12",
92
+ "styled-components": "^6.1.13",
92
93
  "ts-node": "^10.9.2",
93
- "tsx": "^4.17.0",
94
- "typescript": "5.5.4",
95
- "vite": "^5.4.2"
94
+ "typescript": "5.6.2",
95
+ "vite": "^5.4.2",
96
+ "vitest": "^2.1.1",
97
+ "@sanity/gherkin-driver": "^0.0.1"
96
98
  },
97
99
  "peerDependencies": {
98
100
  "@sanity/block-tools": "^3.47.1",
@@ -100,8 +102,8 @@
100
102
  "@sanity/types": "^3.47.1",
101
103
  "@sanity/util": "^3.47.1",
102
104
  "react": "^16.9 || ^17 || ^18",
103
- "rxjs": "^7",
104
- "styled-components": "^6.1"
105
+ "rxjs": "^7.8.1",
106
+ "styled-components": "^6.1.13"
105
107
  },
106
108
  "engines": {
107
109
  "node": ">=18"
@@ -115,11 +117,10 @@
115
117
  "check:types": "tsc",
116
118
  "clean": "del .turbo && del lib && del node_modules",
117
119
  "dev": "pkg-utils watch",
118
- "dev:e2e-server": "cd ./e2e-tests/ && tsx serve",
119
120
  "lint:fix": "biome lint --write .",
120
- "test": "jest",
121
+ "test": "vitest --run",
122
+ "test:watch": "vitest",
121
123
  "test:e2e": "jest --config=e2e-tests/e2e.config.ts",
122
- "test:e2e:watch": "jest --config=e2e-tests/e2e.config.ts --watch",
123
- "test:watch": "jest --watch"
124
+ "test:e2e:watch": "jest --config=e2e-tests/e2e.config.ts --watch"
124
125
  }
125
126
  }
@@ -161,15 +161,15 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
161
161
 
162
162
  const rangeDecorationsRef = useRef(rangeDecorations)
163
163
 
164
- const {change$, schemaTypes} = portableTextEditor
164
+ const {editorActor, schemaTypes} = portableTextEditor
165
165
  const slateEditor = useSlate()
166
166
 
167
167
  const blockTypeName = schemaTypes.block.name
168
168
 
169
169
  // React/UI-specific plugins
170
170
  const withInsertData = useMemo(
171
- () => createWithInsertData(change$, schemaTypes, keyGenerator),
172
- [change$, keyGenerator, schemaTypes],
171
+ () => createWithInsertData(editorActor, schemaTypes, keyGenerator),
172
+ [editorActor, keyGenerator, schemaTypes],
173
173
  )
174
174
  const withHotKeys = useMemo(
175
175
  () => createWithHotkeys(schemaTypes, portableTextEditor, hotkeys),
@@ -278,13 +278,16 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
278
278
  // Output selection here in those cases where the editor selection was the same, and there are no set_selection operations made.
279
279
  // The selection is usually automatically emitted to change$ by the withPortableTextSelections plugin whenever there is a set_selection operation applied.
280
280
  if (!slateEditor.operations.some((o) => o.type === 'set_selection')) {
281
- change$.next({type: 'selection', selection: normalizedSelection})
281
+ editorActor.send({
282
+ type: 'selection',
283
+ selection: normalizedSelection,
284
+ })
282
285
  }
283
286
  slateEditor.onChange()
284
287
  }
285
288
  }
286
289
  }
287
- }, [propsSelection, slateEditor, blockTypeName, change$])
290
+ }, [editorActor, propsSelection, slateEditor])
288
291
 
289
292
  const syncRangeDecorations = useCallback(
290
293
  (operation?: Operation) => {
@@ -348,28 +351,24 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
348
351
  [portableTextEditor, rangeDecorations, schemaTypes, slateEditor],
349
352
  )
350
353
 
351
- // Subscribe to change$ and restore selection from props when the editor has been initialized properly with it's value
354
+ // Restore selection from props when the editor has been initialized properly with it's value
352
355
  useEffect(() => {
353
- // debug('Subscribing to editor changes$')
354
- const sub = change$.subscribe((next: EditorChange): void => {
355
- switch (next.type) {
356
- case 'ready':
357
- restoreSelectionFromProps()
358
- break
359
- case 'invalidValue':
360
- setHasInvalidValue(true)
361
- break
362
- case 'value':
363
- setHasInvalidValue(false)
364
- break
365
- default:
366
- }
356
+ const onReady = editorActor.on('ready', () => {
357
+ restoreSelectionFromProps()
367
358
  })
359
+ const onInvalidValue = editorActor.on('invalid value', () => {
360
+ setHasInvalidValue(true)
361
+ })
362
+ const onValueChanged = editorActor.on('value changed', () => {
363
+ setHasInvalidValue(false)
364
+ })
365
+
368
366
  return () => {
369
- // debug('Unsubscribing to changes$')
370
- sub.unsubscribe()
367
+ onReady.unsubscribe()
368
+ onInvalidValue.unsubscribe()
369
+ onValueChanged.unsubscribe()
371
370
  }
372
- }, [change$, restoreSelectionFromProps])
371
+ }, [editorActor, restoreSelectionFromProps])
373
372
 
374
373
  // Restore selection from props when it changes
375
374
  useEffect(() => {
@@ -451,7 +450,7 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
451
450
  slateEditor.insertData(event.clipboardData)
452
451
  } else {
453
452
  // Resolve it as promise (can be either async promise or sync return value)
454
- change$.next({type: 'loading', isLoading: true})
453
+ editorActor.send({type: 'loading'})
455
454
  Promise.resolve(onPasteResult)
456
455
  .then((result) => {
457
456
  debug('Custom paste function from client resolved', result)
@@ -476,11 +475,11 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
476
475
  return error
477
476
  })
478
477
  .finally(() => {
479
- change$.next({type: 'loading', isLoading: false})
478
+ editorActor.send({type: 'done loading'})
480
479
  })
481
480
  }
482
481
  },
483
- [change$, onPaste, portableTextEditor, schemaTypes, slateEditor],
482
+ [onPaste, portableTextEditor, schemaTypes, slateEditor],
484
483
  )
485
484
 
486
485
  const handleOnFocus: FocusEventHandler<HTMLDivElement> = useCallback(
@@ -495,18 +494,18 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
495
494
  Transforms.select(slateEditor, Editor.start(slateEditor, []))
496
495
  slateEditor.onChange()
497
496
  }
498
- change$.next({type: 'focus', event})
497
+ editorActor.send({type: 'focus', event})
499
498
  const newSelection = PortableTextEditor.getSelection(portableTextEditor)
500
499
  // If the selection is the same, emit it explicitly here as there is no actual onChange event triggered.
501
500
  if (selection === newSelection) {
502
- change$.next({
501
+ editorActor.send({
503
502
  type: 'selection',
504
503
  selection,
505
504
  })
506
505
  }
507
506
  }
508
507
  },
509
- [onFocus, portableTextEditor, change$, slateEditor],
508
+ [editorActor, onFocus, portableTextEditor, slateEditor],
510
509
  )
511
510
 
512
511
  const handleClick = useCallback(
@@ -542,10 +541,10 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
542
541
  onBlur(event)
543
542
  }
544
543
  if (!event.isPropagationStopped()) {
545
- change$.next({type: 'blur', event})
544
+ editorActor.send({type: 'blur', event})
546
545
  }
547
546
  },
548
- [change$, onBlur],
547
+ [editorActor, onBlur],
549
548
  )
550
549
 
551
550
  const handleOnBeforeInput = useCallback(
@@ -11,12 +11,14 @@ import type {
11
11
  } from '@sanity/types'
12
12
  import {Component, type MutableRefObject, type PropsWithChildren} from 'react'
13
13
  import {Subject} from 'rxjs'
14
+ import {createActor, type Subscription} from 'xstate'
14
15
  import type {
15
16
  EditableAPI,
16
17
  EditableAPIDeleteOptions,
17
18
  EditorChange,
18
19
  EditorChanges,
19
20
  EditorSelection,
21
+ MutationChange,
20
22
  PatchObservable,
21
23
  PortableTextMemberSchemaTypes,
22
24
  } from '../types/editor'
@@ -25,6 +27,7 @@ import {getPortableTextMemberSchemaTypes} from '../utils/getPortableTextMemberSc
25
27
  import {compileType} from '../utils/schema'
26
28
  import {SlateContainer} from './components/SlateContainer'
27
29
  import {Synchronizer} from './components/Synchronizer'
30
+ import {editorMachine, type EditorActor} from './editor-machine'
28
31
  import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
29
32
  import {
30
33
  defaultKeyGenerator,
@@ -92,6 +95,11 @@ export type PortableTextEditorProps = PropsWithChildren<{
92
95
  * @public
93
96
  */
94
97
  export class PortableTextEditor extends Component<PortableTextEditorProps> {
98
+ /**
99
+ * @internal
100
+ * Don't use this API directly. It's subject to change.
101
+ */
102
+ public editorActor: EditorActor
95
103
  /**
96
104
  * An observable of all the editor changes.
97
105
  */
@@ -118,7 +126,8 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
118
126
  )
119
127
  }
120
128
 
121
- this.change$.next({type: 'loading', isLoading: true})
129
+ this.editorActor = createActor(editorMachine)
130
+ this.editorActor.start()
122
131
 
123
132
  this.schemaTypes = getPortableTextMemberSchemaTypes(
124
133
  props.schemaType.hasOwnProperty('jsonType')
@@ -154,8 +163,7 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
154
163
  }
155
164
 
156
165
  render() {
157
- const {onChange, value, children, patches$, incomingPatches$} = this.props
158
- const {change$} = this
166
+ const {value, children, patches$, incomingPatches$} = this.props
159
167
  const _patches$ = incomingPatches$ || patches$ // Backward compatibility
160
168
 
161
169
  const maxBlocks =
@@ -176,11 +184,20 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
176
184
  <PortableTextEditorKeyGeneratorContext.Provider value={keyGenerator}>
177
185
  <PortableTextEditorContext.Provider value={this}>
178
186
  <PortableTextEditorReadOnlyContext.Provider value={readOnly}>
179
- <PortableTextEditorSelectionProvider change$={change$}>
187
+ <PortableTextEditorSelectionProvider
188
+ editorActor={this.editorActor}
189
+ >
180
190
  <Synchronizer
181
- change$={change$}
191
+ editorActor={this.editorActor}
182
192
  getValue={this.getValue}
183
- onChange={onChange}
193
+ onChange={(change) => {
194
+ this.props.onChange(change)
195
+ /**
196
+ * For backwards compatibility, we relay all changes to the
197
+ * `change$` Subject as well.
198
+ */
199
+ this.change$.next(change)
200
+ }}
184
201
  value={value}
185
202
  />
186
203
  {children}
@@ -1,7 +1,7 @@
1
- import {describe, expect, it, jest} from '@jest/globals'
2
1
  import type {PortableTextBlock} from '@sanity/types'
3
2
  import {render, waitFor} from '@testing-library/react'
4
3
  import {createRef, type RefObject} from 'react'
4
+ import {describe, expect, it, vi} from 'vitest'
5
5
  import type {EditorSelection} from '../..'
6
6
  import {PortableTextEditor} from '../PortableTextEditor'
7
7
  import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
@@ -18,7 +18,7 @@ const renderPlaceholder = () => 'Jot something down here'
18
18
  describe('initialization', () => {
19
19
  it('receives initial onChange events and has custom placeholder', async () => {
20
20
  const editorRef: RefObject<PortableTextEditor> = createRef()
21
- const onChange = jest.fn()
21
+ const onChange = vi.fn()
22
22
  const {container} = render(
23
23
  <PortableTextEditorTester
24
24
  onChange={onChange}
@@ -88,7 +88,7 @@ describe('initialization', () => {
88
88
  })
89
89
  it('takes value from props and confirms it by emitting value change event', async () => {
90
90
  const initialValue = [helloBlock]
91
- const onChange = jest.fn()
91
+ const onChange = vi.fn()
92
92
  const editorRef = createRef<PortableTextEditor>()
93
93
  render(
94
94
  <PortableTextEditorTester
@@ -120,7 +120,7 @@ describe('initialization', () => {
120
120
  focus: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
121
121
  backward: false,
122
122
  }
123
- const onChange = jest.fn()
123
+ const onChange = vi.fn()
124
124
  render(
125
125
  <PortableTextEditorTester
126
126
  onChange={onChange}
@@ -164,7 +164,7 @@ describe('initialization', () => {
164
164
  focus: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 3},
165
165
  backward: false,
166
166
  }
167
- const onChange = jest.fn()
167
+ const onChange = vi.fn()
168
168
  const {rerender} = render(
169
169
  <PortableTextEditorTester
170
170
  onChange={onChange}
@@ -223,7 +223,7 @@ describe('initialization', () => {
223
223
  anchor: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
224
224
  focus: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
225
225
  }
226
- const onChange = jest.fn()
226
+ const onChange = vi.fn()
227
227
  render(
228
228
  <PortableTextEditorTester
229
229
  onChange={onChange}
@@ -266,7 +266,7 @@ describe('initialization', () => {
266
266
  anchor: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
267
267
  focus: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
268
268
  }
269
- const onChange = jest.fn()
269
+ const onChange = vi.fn()
270
270
  let _rerender: any
271
271
  await waitFor(() => {
272
272
  render(
@@ -300,7 +300,7 @@ describe('initialization', () => {
300
300
  expect(onChange).toHaveBeenCalledWith({type: 'value', value})
301
301
  })
302
302
  value = [{_type: 'banana', _key: '123'}]
303
- const newOnChange = jest.fn()
303
+ const newOnChange = vi.fn()
304
304
  _rerender(
305
305
  <PortableTextEditorTester
306
306
  onChange={newOnChange}
@@ -352,7 +352,7 @@ describe('initialization', () => {
352
352
  anchor: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
353
353
  focus: {path: [{_key: '123'}, 'children', {_key: '567'}], offset: 2},
354
354
  }
355
- const onChange = jest.fn()
355
+ const onChange = vi.fn()
356
356
  render(
357
357
  <PortableTextEditorTester
358
358
  onChange={onChange}
@@ -1,4 +1,3 @@
1
- import {jest} from '@jest/globals'
2
1
  import {Schema} from '@sanity/schema'
3
2
  import {defineArrayMember, defineField} from '@sanity/types'
4
3
  import {
@@ -8,6 +7,7 @@ import {
8
7
  useMemo,
9
8
  type ForwardedRef,
10
9
  } from 'react'
10
+ import {vi} from 'vitest'
11
11
  import {
12
12
  PortableTextEditable,
13
13
  PortableTextEditor,
@@ -100,10 +100,7 @@ export const PortableTextEditorTester = forwardRef(
100
100
  key++
101
101
  return `${key}`
102
102
  }, [])
103
- const onChange = useMemo(
104
- () => props.onChange || jest.fn(),
105
- [props.onChange],
106
- )
103
+ const onChange = useMemo(() => props.onChange || vi.fn(), [props.onChange])
107
104
  return (
108
105
  <PortableTextEditor
109
106
  schemaType={props.schemaType}
@@ -1,7 +1,7 @@
1
- import {describe, expect, it, jest} from '@jest/globals'
2
1
  import type {PortableTextBlock} from '@sanity/types'
3
2
  import {render, waitFor} from '@testing-library/react'
4
3
  import {createRef, type ReactNode, type RefObject} from 'react'
4
+ import {describe, expect, it, vi} from 'vitest'
5
5
  import type {RangeDecoration} from '../..'
6
6
  import type {PortableTextEditor} from '../PortableTextEditor'
7
7
  import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
@@ -23,7 +23,7 @@ const RangeDecorationTestComponent = ({children}: {children?: ReactNode}) => {
23
23
  describe('RangeDecorations', () => {
24
24
  it('only render range decorations as necessary', async () => {
25
25
  const editorRef: RefObject<PortableTextEditor> = createRef()
26
- const onChange = jest.fn()
26
+ const onChange = vi.fn()
27
27
  const value = [helloBlock]
28
28
  let rangeDecorations: RangeDecoration[] = [
29
29
  {
@@ -1,9 +1,29 @@
1
- import {describe, expect, it, jest} from '@jest/globals'
2
1
  import {fireEvent, render, waitFor} from '@testing-library/react'
3
- import {createRef, type RefObject} from 'react'
2
+ import {act, createRef, type RefObject} from 'react'
3
+ import {describe, expect, it, vi} from 'vitest'
4
4
  import {PortableTextEditor} from '../PortableTextEditor'
5
5
  import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
6
- import {getEditableElement} from './utils'
6
+
7
+ async function getEditableElement(
8
+ component: ReturnType<typeof render>,
9
+ ): Promise<Element> {
10
+ await act(async () => component)
11
+ const element = component.container.querySelector(
12
+ '[data-slate-editor="true"]',
13
+ )
14
+ if (!element) {
15
+ throw new Error('Could not find element')
16
+ }
17
+ /**
18
+ * Manually add this because JSDom doesn't implement this and Slate checks for it
19
+ * internally before doing stuff.
20
+ *
21
+ * https://github.com/jsdom/jsdom/issues/1670
22
+ */
23
+ // @ts-ignore
24
+ element.isContentEditable = true
25
+ return element
26
+ }
7
27
 
8
28
  describe('adds empty text block if its needed', () => {
9
29
  const newBlock = {
@@ -34,7 +54,7 @@ describe('adds empty text block if its needed', () => {
34
54
  }
35
55
 
36
56
  const editorRef: RefObject<PortableTextEditor> = createRef()
37
- const onChange = jest.fn()
57
+ const onChange = vi.fn()
38
58
  const component = render(
39
59
  <PortableTextEditorTester
40
60
  onChange={onChange}
@@ -96,7 +116,7 @@ describe('adds empty text block if its needed', () => {
96
116
  }
97
117
 
98
118
  const editorRef: RefObject<PortableTextEditor> = createRef()
99
- const onChange = jest.fn()
119
+ const onChange = vi.fn()
100
120
  const component = render(
101
121
  <PortableTextEditorTester
102
122
  onChange={onChange}
@@ -151,7 +171,7 @@ describe('adds empty text block if its needed', () => {
151
171
  }
152
172
 
153
173
  const editorRef: RefObject<PortableTextEditor> = createRef()
154
- const onChange = jest.fn()
174
+ const onChange = vi.fn()
155
175
  const component = render(
156
176
  <PortableTextEditorTester
157
177
  onChange={onChange}
@@ -217,7 +237,7 @@ describe('adds empty text block if its needed', () => {
217
237
  }
218
238
 
219
239
  const editorRef: RefObject<PortableTextEditor> = createRef()
220
- const onChange = jest.fn()
240
+ const onChange = vi.fn()
221
241
  const component = render(
222
242
  <PortableTextEditorTester
223
243
  onChange={onChange}
@@ -1,8 +1,8 @@
1
- import {describe, expect, jest, test} from '@jest/globals'
2
1
  import {Schema} from '@sanity/schema'
3
2
  import type {PortableTextBlock} from '@sanity/types'
4
3
  import {render, waitFor} from '@testing-library/react'
5
4
  import {createRef, type RefObject} from 'react'
5
+ import {describe, expect, test, vi} from 'vitest'
6
6
  import type {EditorChange, EditorSelection} from '../../types/editor'
7
7
  import {PortableTextEditable} from '../Editable'
8
8
  import {PortableTextEditor} from '../PortableTextEditor'
@@ -35,7 +35,7 @@ describe(PortableTextEditor.insertBlock.name, () => {
35
35
  style: 'normal',
36
36
  }
37
37
  const initialValue: Array<PortableTextBlock> = [emptyTextBlock]
38
- const onChange: (change: EditorChange) => void = jest.fn()
38
+ const onChange: (change: EditorChange) => void = vi.fn()
39
39
 
40
40
  render(
41
41
  <PortableTextEditor
@@ -104,7 +104,7 @@ describe(PortableTextEditor.insertBlock.name, () => {
104
104
  style: 'normal',
105
105
  }
106
106
  const initialValue: Array<PortableTextBlock> = [nonEmptyTextBlock]
107
- const onChange: (change: EditorChange) => void = jest.fn()
107
+ const onChange: (change: EditorChange) => void = vi.fn()
108
108
 
109
109
  render(
110
110
  <PortableTextEditor
@@ -177,7 +177,7 @@ describe(PortableTextEditor.insertBlock.name, () => {
177
177
  _type: 'image',
178
178
  }
179
179
  const initialValue: Array<PortableTextBlock> = [emptyTextBlock, imageBlock]
180
- const onChange: (change: EditorChange) => void = jest.fn()
180
+ const onChange: (change: EditorChange) => void = vi.fn()
181
181
 
182
182
  render(
183
183
  <PortableTextEditor
@@ -1,7 +1,7 @@
1
- import {describe, expect, it, jest} from '@jest/globals'
2
1
  import type {PortableTextBlock} from '@sanity/types'
3
2
  import {render, waitFor} from '@testing-library/react'
4
3
  import {createRef, type RefObject} from 'react'
4
+ import {describe, expect, it, vi} from 'vitest'
5
5
  import {PortableTextEditor} from '../PortableTextEditor'
6
6
  import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
7
7
 
@@ -24,7 +24,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
24
24
  },
25
25
  ]
26
26
 
27
- const onChange = jest.fn()
27
+ const onChange = vi.fn()
28
28
  render(
29
29
  <PortableTextEditorTester
30
30
  onChange={onChange}
@@ -80,7 +80,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
80
80
  },
81
81
  ]
82
82
 
83
- const onChange = jest.fn()
83
+ const onChange = vi.fn()
84
84
  render(
85
85
  <PortableTextEditorTester
86
86
  onChange={onChange}
@@ -137,7 +137,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
137
137
  },
138
138
  ]
139
139
 
140
- const onChange = jest.fn()
140
+ const onChange = vi.fn()
141
141
  render(
142
142
  <PortableTextEditorTester
143
143
  onChange={onChange}
@@ -209,7 +209,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
209
209
  },
210
210
  ]
211
211
 
212
- const onChange = jest.fn()
212
+ const onChange = vi.fn()
213
213
  render(
214
214
  <PortableTextEditorTester
215
215
  onChange={onChange}
@@ -273,7 +273,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
273
273
  },
274
274
  ]
275
275
 
276
- const onChange = jest.fn()
276
+ const onChange = vi.fn()
277
277
  render(
278
278
  <PortableTextEditorTester
279
279
  onChange={onChange}
@@ -316,7 +316,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
316
316
  const editorRef: RefObject<PortableTextEditor> = createRef()
317
317
  const initialValue = [] as PortableTextBlock[]
318
318
 
319
- const onChange = jest.fn()
319
+ const onChange = vi.fn()
320
320
  render(
321
321
  <PortableTextEditorTester
322
322
  onChange={onChange}