@portabletext/editor 1.0.19 → 1.1.1
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/lib/index.d.mts +142 -67
- package/lib/index.d.ts +142 -67
- package/lib/index.esm.js +1130 -371
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +1130 -371
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1130 -371
- package/lib/index.mjs.map +1 -1
- package/package.json +4 -18
- package/src/editor/Editable.tsx +128 -55
- package/src/editor/PortableTextEditor.tsx +66 -32
- package/src/editor/__tests__/PortableTextEditor.test.tsx +44 -18
- package/src/editor/__tests__/PortableTextEditorTester.tsx +50 -38
- package/src/editor/__tests__/RangeDecorations.test.tsx +4 -6
- package/src/editor/__tests__/handleClick.test.tsx +28 -9
- package/src/editor/__tests__/insert-block.test.tsx +24 -8
- package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +31 -63
- package/src/editor/__tests__/utils.ts +10 -4
- package/src/editor/components/DraggableBlock.tsx +36 -13
- package/src/editor/components/Element.tsx +73 -33
- package/src/editor/components/Leaf.tsx +114 -76
- package/src/editor/components/SlateContainer.tsx +14 -7
- package/src/editor/components/Synchronizer.tsx +8 -5
- package/src/editor/hooks/usePortableTextEditor.ts +3 -3
- package/src/editor/hooks/usePortableTextEditorSelection.tsx +10 -4
- package/src/editor/hooks/useSyncValue.test.tsx +9 -4
- package/src/editor/hooks/useSyncValue.ts +198 -133
- package/src/editor/nodes/DefaultAnnotation.tsx +6 -4
- package/src/editor/nodes/DefaultObject.tsx +1 -1
- package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +23 -8
- package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +26 -9
- package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +15 -5
- package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +60 -19
- package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +5 -3
- package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +4 -2
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +61 -19
- package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +6 -3
- package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +30 -13
- package/src/editor/plugins/createWithEditableAPI.ts +361 -131
- package/src/editor/plugins/createWithHotKeys.ts +46 -130
- package/src/editor/plugins/createWithInsertBreak.ts +167 -28
- package/src/editor/plugins/createWithInsertData.ts +66 -30
- package/src/editor/plugins/createWithMaxBlocks.ts +6 -3
- package/src/editor/plugins/createWithObjectKeys.ts +7 -3
- package/src/editor/plugins/createWithPatches.ts +66 -24
- package/src/editor/plugins/createWithPlaceholderBlock.ts +9 -5
- package/src/editor/plugins/createWithPortableTextBlockStyle.ts +17 -7
- package/src/editor/plugins/createWithPortableTextLists.ts +21 -9
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +217 -52
- package/src/editor/plugins/createWithPortableTextSelections.ts +11 -9
- package/src/editor/plugins/createWithSchemaTypes.ts +26 -10
- package/src/editor/plugins/createWithUndoRedo.ts +106 -27
- package/src/editor/plugins/createWithUtils.ts +33 -11
- package/src/editor/plugins/index.ts +34 -13
- package/src/types/editor.ts +73 -44
- package/src/types/options.ts +7 -5
- package/src/types/slate.ts +6 -6
- package/src/utils/__tests__/dmpToOperations.test.ts +41 -16
- package/src/utils/__tests__/operationToPatches.test.ts +4 -3
- package/src/utils/__tests__/patchToOperations.test.ts +16 -5
- package/src/utils/__tests__/ranges.test.ts +9 -4
- package/src/utils/__tests__/valueNormalization.test.tsx +12 -4
- package/src/utils/__tests__/values.test.ts +0 -1
- package/src/utils/applyPatch.ts +78 -29
- package/src/utils/getPortableTextMemberSchemaTypes.ts +38 -23
- package/src/utils/operationToPatches.ts +123 -44
- package/src/utils/paths.ts +26 -9
- package/src/utils/ranges.ts +16 -10
- package/src/utils/selection.ts +21 -9
- package/src/utils/ucs2Indices.ts +2 -2
- package/src/utils/validateValue.ts +118 -45
- package/src/utils/values.ts +38 -17
- package/src/utils/weakMaps.ts +20 -10
- package/src/utils/withChanges.ts +5 -3
- package/src/utils/withUndoRedo.ts +1 -1
- package/src/utils/withoutPatching.ts +1 -1
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {describe, expect, it, jest} from '@jest/globals'
|
|
2
|
-
|
|
3
|
-
import {type PortableTextBlock} from '@sanity/types'
|
|
2
|
+
import type {PortableTextBlock} from '@sanity/types'
|
|
4
3
|
import {render, waitFor} from '@testing-library/react'
|
|
5
4
|
import {createRef, type RefObject} from 'react'
|
|
6
|
-
|
|
7
|
-
import {type EditorSelection} from '../..'
|
|
5
|
+
import type {EditorSelection} from '../..'
|
|
8
6
|
import {PortableTextEditor} from '../PortableTextEditor'
|
|
9
7
|
import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
|
|
10
8
|
|
|
@@ -102,10 +100,15 @@ describe('initialization', () => {
|
|
|
102
100
|
)
|
|
103
101
|
const normalizedEditorValue = [{...initialValue[0], style: 'normal'}]
|
|
104
102
|
await waitFor(() => {
|
|
105
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
103
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
104
|
+
type: 'value',
|
|
105
|
+
value: initialValue,
|
|
106
|
+
})
|
|
106
107
|
})
|
|
107
108
|
if (editorRef.current) {
|
|
108
|
-
expect(PortableTextEditor.getValue(editorRef.current)).toStrictEqual(
|
|
109
|
+
expect(PortableTextEditor.getValue(editorRef.current)).toStrictEqual(
|
|
110
|
+
normalizedEditorValue,
|
|
111
|
+
)
|
|
109
112
|
}
|
|
110
113
|
})
|
|
111
114
|
|
|
@@ -130,7 +133,10 @@ describe('initialization', () => {
|
|
|
130
133
|
|
|
131
134
|
await waitFor(() => {
|
|
132
135
|
if (editorRef.current) {
|
|
133
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
136
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
137
|
+
type: 'value',
|
|
138
|
+
value: initialValue,
|
|
139
|
+
})
|
|
134
140
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
135
141
|
}
|
|
136
142
|
})
|
|
@@ -138,7 +144,9 @@ describe('initialization', () => {
|
|
|
138
144
|
await waitFor(() => {
|
|
139
145
|
if (editorRef.current) {
|
|
140
146
|
PortableTextEditor.focus(editorRef.current)
|
|
141
|
-
expect(
|
|
147
|
+
expect(
|
|
148
|
+
PortableTextEditor.getSelection(editorRef.current),
|
|
149
|
+
).toStrictEqual(initialSelection)
|
|
142
150
|
}
|
|
143
151
|
})
|
|
144
152
|
})
|
|
@@ -169,7 +177,10 @@ describe('initialization', () => {
|
|
|
169
177
|
|
|
170
178
|
await waitFor(() => {
|
|
171
179
|
if (editorRef.current) {
|
|
172
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
180
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
181
|
+
type: 'value',
|
|
182
|
+
value: initialValue,
|
|
183
|
+
})
|
|
173
184
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
174
185
|
}
|
|
175
186
|
})
|
|
@@ -181,7 +192,9 @@ describe('initialization', () => {
|
|
|
181
192
|
|
|
182
193
|
// Test for object equality here!
|
|
183
194
|
const anotherSel = PortableTextEditor.getSelection(editorRef.current)
|
|
184
|
-
expect(
|
|
195
|
+
expect(
|
|
196
|
+
PortableTextEditor.getSelection(editorRef.current),
|
|
197
|
+
).toStrictEqual(initialSelection)
|
|
185
198
|
expect(sel).toBe(anotherSel)
|
|
186
199
|
}
|
|
187
200
|
})
|
|
@@ -196,7 +209,9 @@ describe('initialization', () => {
|
|
|
196
209
|
)
|
|
197
210
|
waitFor(() => {
|
|
198
211
|
if (editorRef.current) {
|
|
199
|
-
expect(PortableTextEditor.getSelection(editorRef.current)).toEqual(
|
|
212
|
+
expect(PortableTextEditor.getSelection(editorRef.current)).toEqual(
|
|
213
|
+
newSelection,
|
|
214
|
+
)
|
|
200
215
|
}
|
|
201
216
|
})
|
|
202
217
|
})
|
|
@@ -225,7 +240,8 @@ describe('initialization', () => {
|
|
|
225
240
|
value: initialValue,
|
|
226
241
|
resolution: {
|
|
227
242
|
action: 'Unset the value',
|
|
228
|
-
description:
|
|
243
|
+
description:
|
|
244
|
+
'Editor value must be an array of Portable Text blocks, or undefined.',
|
|
229
245
|
item: initialValue,
|
|
230
246
|
patches: [
|
|
231
247
|
{
|
|
@@ -235,7 +251,10 @@ describe('initialization', () => {
|
|
|
235
251
|
],
|
|
236
252
|
},
|
|
237
253
|
})
|
|
238
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
254
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
255
|
+
type: 'value',
|
|
256
|
+
value: initialValue,
|
|
257
|
+
})
|
|
239
258
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
240
259
|
}
|
|
241
260
|
})
|
|
@@ -267,7 +286,8 @@ describe('initialization', () => {
|
|
|
267
286
|
value,
|
|
268
287
|
resolution: {
|
|
269
288
|
action: 'Unset the value',
|
|
270
|
-
description:
|
|
289
|
+
description:
|
|
290
|
+
'Editor value must be an array of Portable Text blocks, or undefined.',
|
|
271
291
|
item: value,
|
|
272
292
|
patches: [
|
|
273
293
|
{
|
|
@@ -306,7 +326,8 @@ describe('initialization', () => {
|
|
|
306
326
|
],
|
|
307
327
|
i18n: {
|
|
308
328
|
action: 'inputs.portable-text.invalid-value.disallowed-type.action',
|
|
309
|
-
description:
|
|
329
|
+
description:
|
|
330
|
+
'inputs.portable-text.invalid-value.disallowed-type.description',
|
|
310
331
|
values: {
|
|
311
332
|
key: '123',
|
|
312
333
|
typeName: 'banana',
|
|
@@ -351,8 +372,10 @@ describe('initialization', () => {
|
|
|
351
372
|
description:
|
|
352
373
|
"Child with _key 'def' in block with key 'abc' has missing or invalid text property!",
|
|
353
374
|
i18n: {
|
|
354
|
-
action:
|
|
355
|
-
|
|
375
|
+
action:
|
|
376
|
+
'inputs.portable-text.invalid-value.invalid-span-text.action',
|
|
377
|
+
description:
|
|
378
|
+
'inputs.portable-text.invalid-value.invalid-span-text.description',
|
|
356
379
|
values: {
|
|
357
380
|
key: 'abc',
|
|
358
381
|
childKey: 'def',
|
|
@@ -394,7 +417,10 @@ describe('initialization', () => {
|
|
|
394
417
|
})
|
|
395
418
|
}
|
|
396
419
|
})
|
|
397
|
-
expect(onChange).not.toHaveBeenCalledWith({
|
|
420
|
+
expect(onChange).not.toHaveBeenCalledWith({
|
|
421
|
+
type: 'value',
|
|
422
|
+
value: initialValue,
|
|
423
|
+
})
|
|
398
424
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
399
425
|
})
|
|
400
426
|
})
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import {jest} from '@jest/globals'
|
|
2
2
|
import {Schema} from '@sanity/schema'
|
|
3
3
|
import {defineArrayMember, defineField} from '@sanity/types'
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
forwardRef,
|
|
6
|
+
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useMemo,
|
|
9
|
+
type ForwardedRef,
|
|
10
|
+
} from 'react'
|
|
6
11
|
import {
|
|
7
12
|
PortableTextEditable,
|
|
8
|
-
type PortableTextEditableProps,
|
|
9
13
|
PortableTextEditor,
|
|
14
|
+
type PortableTextEditableProps,
|
|
10
15
|
type PortableTextEditorProps,
|
|
11
16
|
} from '../../index'
|
|
12
17
|
|
|
@@ -74,42 +79,49 @@ const schema = Schema.compile({
|
|
|
74
79
|
|
|
75
80
|
let key = 0
|
|
76
81
|
|
|
77
|
-
export const PortableTextEditorTester = forwardRef(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
export const PortableTextEditorTester = forwardRef(
|
|
83
|
+
function PortableTextEditorTester(
|
|
84
|
+
props: Partial<
|
|
85
|
+
Omit<PortableTextEditorProps, 'type' | 'onChange' | 'value'>
|
|
86
|
+
> & {
|
|
87
|
+
onChange?: PortableTextEditorProps['onChange']
|
|
88
|
+
rangeDecorations?: PortableTextEditableProps['rangeDecorations']
|
|
89
|
+
renderPlaceholder?: PortableTextEditableProps['renderPlaceholder']
|
|
90
|
+
schemaType: PortableTextEditorProps['schemaType']
|
|
91
|
+
selection?: PortableTextEditableProps['selection']
|
|
92
|
+
value?: PortableTextEditorProps['value']
|
|
93
|
+
},
|
|
94
|
+
ref: ForwardedRef<PortableTextEditor>,
|
|
95
|
+
) {
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
key = 0
|
|
98
|
+
}, [])
|
|
99
|
+
const _keyGenerator = useCallback(() => {
|
|
100
|
+
key++
|
|
101
|
+
return `${key}`
|
|
102
|
+
}, [])
|
|
103
|
+
const onChange = useMemo(
|
|
104
|
+
() => props.onChange || jest.fn(),
|
|
105
|
+
[props.onChange],
|
|
106
|
+
)
|
|
107
|
+
return (
|
|
108
|
+
<PortableTextEditor
|
|
109
|
+
schemaType={props.schemaType}
|
|
110
|
+
onChange={onChange}
|
|
111
|
+
value={props.value || undefined}
|
|
112
|
+
keyGenerator={_keyGenerator}
|
|
113
|
+
ref={ref}
|
|
114
|
+
>
|
|
115
|
+
<PortableTextEditable
|
|
116
|
+
selection={props.selection || undefined}
|
|
117
|
+
rangeDecorations={props.rangeDecorations}
|
|
118
|
+
renderPlaceholder={props.renderPlaceholder}
|
|
119
|
+
aria-describedby="desc_foo"
|
|
120
|
+
/>
|
|
121
|
+
</PortableTextEditor>
|
|
122
|
+
)
|
|
85
123
|
},
|
|
86
|
-
|
|
87
|
-
) {
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
key = 0
|
|
90
|
-
}, [])
|
|
91
|
-
const _keyGenerator = useCallback(() => {
|
|
92
|
-
key++
|
|
93
|
-
return `${key}`
|
|
94
|
-
}, [])
|
|
95
|
-
const onChange = useMemo(() => props.onChange || jest.fn(), [props.onChange])
|
|
96
|
-
return (
|
|
97
|
-
<PortableTextEditor
|
|
98
|
-
schemaType={props.schemaType}
|
|
99
|
-
onChange={onChange}
|
|
100
|
-
value={props.value || undefined}
|
|
101
|
-
keyGenerator={_keyGenerator}
|
|
102
|
-
ref={ref}
|
|
103
|
-
>
|
|
104
|
-
<PortableTextEditable
|
|
105
|
-
selection={props.selection || undefined}
|
|
106
|
-
rangeDecorations={props.rangeDecorations}
|
|
107
|
-
renderPlaceholder={props.renderPlaceholder}
|
|
108
|
-
aria-describedby="desc_foo"
|
|
109
|
-
/>
|
|
110
|
-
</PortableTextEditor>
|
|
111
|
-
)
|
|
112
|
-
})
|
|
124
|
+
)
|
|
113
125
|
|
|
114
126
|
export const schemaType = schema.get('body')
|
|
115
127
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import {describe, expect, it, jest} from '@jest/globals'
|
|
2
|
-
|
|
3
|
-
import {type PortableTextBlock} from '@sanity/types'
|
|
2
|
+
import type {PortableTextBlock} from '@sanity/types'
|
|
4
3
|
import {render, waitFor} from '@testing-library/react'
|
|
5
4
|
import {createRef, type ReactNode, type RefObject} from 'react'
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import {type PortableTextEditor} from '../PortableTextEditor'
|
|
5
|
+
import type {RangeDecoration} from '../..'
|
|
6
|
+
import type {PortableTextEditor} from '../PortableTextEditor'
|
|
9
7
|
import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
|
|
10
8
|
|
|
11
9
|
const helloBlock: PortableTextBlock = {
|
|
@@ -23,7 +21,7 @@ const RangeDecorationTestComponent = ({children}: {children?: ReactNode}) => {
|
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
describe('RangeDecorations', () => {
|
|
26
|
-
it
|
|
24
|
+
it('only render range decorations as necessary', async () => {
|
|
27
25
|
const editorRef: RefObject<PortableTextEditor> = createRef()
|
|
28
26
|
const onChange = jest.fn()
|
|
29
27
|
const value = [helloBlock]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {describe, expect, it, jest} from '@jest/globals'
|
|
2
2
|
import {fireEvent, render, waitFor} from '@testing-library/react'
|
|
3
3
|
import {createRef, type RefObject} from 'react'
|
|
4
|
-
|
|
5
4
|
import {PortableTextEditor} from '../PortableTextEditor'
|
|
6
5
|
import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
|
|
7
6
|
import {getEditableElement} from './utils'
|
|
@@ -47,7 +46,10 @@ describe('adds empty text block if its needed', () => {
|
|
|
47
46
|
|
|
48
47
|
await waitFor(() => {
|
|
49
48
|
if (editorRef.current) {
|
|
50
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
49
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
50
|
+
type: 'value',
|
|
51
|
+
value: initialValue,
|
|
52
|
+
})
|
|
51
53
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
52
54
|
}
|
|
53
55
|
})
|
|
@@ -59,7 +61,10 @@ describe('adds empty text block if its needed', () => {
|
|
|
59
61
|
PortableTextEditor.focus(editorRef.current)
|
|
60
62
|
PortableTextEditor.select(editorRef.current, initialSelection)
|
|
61
63
|
fireEvent.click(element)
|
|
62
|
-
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
64
|
+
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
65
|
+
initialValue[0],
|
|
66
|
+
newBlock,
|
|
67
|
+
])
|
|
63
68
|
}
|
|
64
69
|
})
|
|
65
70
|
})
|
|
@@ -107,7 +112,9 @@ describe('adds empty text block if its needed', () => {
|
|
|
107
112
|
PortableTextEditor.focus(editorRef.current)
|
|
108
113
|
PortableTextEditor.select(editorRef.current, initialSelection)
|
|
109
114
|
fireEvent.click(element)
|
|
110
|
-
expect(PortableTextEditor.getValue(editorRef.current)).toEqual(
|
|
115
|
+
expect(PortableTextEditor.getValue(editorRef.current)).toEqual(
|
|
116
|
+
initialValue,
|
|
117
|
+
)
|
|
111
118
|
}
|
|
112
119
|
})
|
|
113
120
|
})
|
|
@@ -156,7 +163,10 @@ describe('adds empty text block if its needed', () => {
|
|
|
156
163
|
|
|
157
164
|
await waitFor(() => {
|
|
158
165
|
if (editorRef.current) {
|
|
159
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
166
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
167
|
+
type: 'value',
|
|
168
|
+
value: initialValue,
|
|
169
|
+
})
|
|
160
170
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
161
171
|
}
|
|
162
172
|
})
|
|
@@ -168,7 +178,9 @@ describe('adds empty text block if its needed', () => {
|
|
|
168
178
|
PortableTextEditor.focus(editorRef.current)
|
|
169
179
|
PortableTextEditor.select(editorRef.current, initialSelection)
|
|
170
180
|
fireEvent.click(element)
|
|
171
|
-
expect(PortableTextEditor.getValue(editorRef.current)).toEqual(
|
|
181
|
+
expect(PortableTextEditor.getValue(editorRef.current)).toEqual(
|
|
182
|
+
initialValue,
|
|
183
|
+
)
|
|
172
184
|
}
|
|
173
185
|
})
|
|
174
186
|
})
|
|
@@ -217,7 +229,10 @@ describe('adds empty text block if its needed', () => {
|
|
|
217
229
|
|
|
218
230
|
await waitFor(() => {
|
|
219
231
|
if (editorRef.current) {
|
|
220
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
232
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
233
|
+
type: 'value',
|
|
234
|
+
value: initialValue,
|
|
235
|
+
})
|
|
221
236
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
222
237
|
}
|
|
223
238
|
})
|
|
@@ -225,13 +240,17 @@ describe('adds empty text block if its needed', () => {
|
|
|
225
240
|
const element = await getEditableElement(component)
|
|
226
241
|
|
|
227
242
|
const editor = editorRef.current
|
|
228
|
-
const inlineType = editor?.schemaTypes.inlineObjects.find(
|
|
243
|
+
const inlineType = editor?.schemaTypes.inlineObjects.find(
|
|
244
|
+
(t) => t.name === 'someObject',
|
|
245
|
+
)
|
|
229
246
|
await waitFor(async () => {
|
|
230
247
|
if (editor && inlineType && element) {
|
|
231
248
|
PortableTextEditor.focus(editor)
|
|
232
249
|
PortableTextEditor.select(editor, initialSelection)
|
|
233
250
|
fireEvent.click(element)
|
|
234
|
-
expect(PortableTextEditor.getValue(editor)).toEqual(
|
|
251
|
+
expect(PortableTextEditor.getValue(editor)).toEqual(
|
|
252
|
+
initialValue.concat(newBlock),
|
|
253
|
+
)
|
|
235
254
|
}
|
|
236
255
|
})
|
|
237
256
|
})
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import {describe, expect, jest, test} from '@jest/globals'
|
|
2
2
|
import {Schema} from '@sanity/schema'
|
|
3
|
-
import
|
|
3
|
+
import type {PortableTextBlock} from '@sanity/types'
|
|
4
4
|
import {render, waitFor} from '@testing-library/react'
|
|
5
5
|
import {createRef, type RefObject} from 'react'
|
|
6
|
-
|
|
7
|
-
import {type EditorChange, type EditorSelection} from '../../types/editor'
|
|
6
|
+
import type {EditorChange, EditorSelection} from '../../types/editor'
|
|
8
7
|
import {PortableTextEditable} from '../Editable'
|
|
9
8
|
import {PortableTextEditor} from '../PortableTextEditor'
|
|
10
9
|
|
|
11
10
|
const schema = Schema.compile({
|
|
12
11
|
types: [
|
|
13
|
-
{
|
|
12
|
+
{
|
|
13
|
+
name: 'portable-text',
|
|
14
|
+
type: 'array',
|
|
15
|
+
of: [{type: 'block'}, {type: 'image'}],
|
|
16
|
+
},
|
|
14
17
|
{name: 'image', type: 'object'},
|
|
15
18
|
],
|
|
16
19
|
}).get('portable-text')
|
|
@@ -49,7 +52,10 @@ describe(PortableTextEditor.insertBlock.name, () => {
|
|
|
49
52
|
// Given an empty text block
|
|
50
53
|
await waitFor(() => {
|
|
51
54
|
if (editorRef.current) {
|
|
52
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
55
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
56
|
+
type: 'value',
|
|
57
|
+
value: initialValue,
|
|
58
|
+
})
|
|
53
59
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
54
60
|
}
|
|
55
61
|
})
|
|
@@ -94,6 +100,7 @@ describe(PortableTextEditor.insertBlock.name, () => {
|
|
|
94
100
|
marks: [],
|
|
95
101
|
},
|
|
96
102
|
],
|
|
103
|
+
markDefs: [],
|
|
97
104
|
style: 'normal',
|
|
98
105
|
}
|
|
99
106
|
const initialValue: Array<PortableTextBlock> = [nonEmptyTextBlock]
|
|
@@ -114,7 +121,10 @@ describe(PortableTextEditor.insertBlock.name, () => {
|
|
|
114
121
|
// Given an non-empty text block
|
|
115
122
|
await waitFor(() => {
|
|
116
123
|
if (editorRef.current) {
|
|
117
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
124
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
125
|
+
type: 'value',
|
|
126
|
+
value: initialValue,
|
|
127
|
+
})
|
|
118
128
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
119
129
|
}
|
|
120
130
|
})
|
|
@@ -184,7 +194,10 @@ describe(PortableTextEditor.insertBlock.name, () => {
|
|
|
184
194
|
// Given an empty text block followed by an image
|
|
185
195
|
await waitFor(() => {
|
|
186
196
|
if (editorRef.current) {
|
|
187
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
197
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
198
|
+
type: 'value',
|
|
199
|
+
value: initialValue,
|
|
200
|
+
})
|
|
188
201
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
189
202
|
}
|
|
190
203
|
})
|
|
@@ -202,7 +215,10 @@ describe(PortableTextEditor.insertBlock.name, () => {
|
|
|
202
215
|
})
|
|
203
216
|
await waitFor(() => {
|
|
204
217
|
if (editorRef.current) {
|
|
205
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
218
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
219
|
+
type: 'selection',
|
|
220
|
+
selection: initialSelection,
|
|
221
|
+
})
|
|
206
222
|
}
|
|
207
223
|
})
|
|
208
224
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {describe, expect, it, jest} from '@jest/globals'
|
|
2
|
-
import
|
|
2
|
+
import type {PortableTextBlock} from '@sanity/types'
|
|
3
3
|
import {render, waitFor} from '@testing-library/react'
|
|
4
4
|
import {createRef, type RefObject} from 'react'
|
|
5
|
-
|
|
6
5
|
import {PortableTextEditor} from '../PortableTextEditor'
|
|
7
6
|
import {PortableTextEditorTester, schemaType} from './PortableTextEditorTester'
|
|
8
7
|
|
|
@@ -35,7 +34,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
35
34
|
/>,
|
|
36
35
|
)
|
|
37
36
|
await waitFor(() => {
|
|
38
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
37
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
38
|
+
type: 'value',
|
|
39
|
+
value: initialValue,
|
|
40
|
+
})
|
|
39
41
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
40
42
|
})
|
|
41
43
|
await waitFor(() => {
|
|
@@ -60,7 +62,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
60
62
|
})
|
|
61
63
|
})
|
|
62
64
|
|
|
63
|
-
it('
|
|
65
|
+
it('self-solves missing .markDefs', async () => {
|
|
64
66
|
const editorRef: RefObject<PortableTextEditor> = createRef()
|
|
65
67
|
const initialValue = [
|
|
66
68
|
{
|
|
@@ -88,7 +90,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
88
90
|
/>,
|
|
89
91
|
)
|
|
90
92
|
await waitFor(() => {
|
|
91
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
93
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
94
|
+
type: 'value',
|
|
95
|
+
value: initialValue,
|
|
96
|
+
})
|
|
92
97
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
93
98
|
})
|
|
94
99
|
await waitFor(() => {
|
|
@@ -106,6 +111,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
106
111
|
marks: [],
|
|
107
112
|
},
|
|
108
113
|
],
|
|
114
|
+
markDefs: [],
|
|
109
115
|
style: 'normal',
|
|
110
116
|
},
|
|
111
117
|
])
|
|
@@ -141,7 +147,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
141
147
|
/>,
|
|
142
148
|
)
|
|
143
149
|
await waitFor(() => {
|
|
144
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
150
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
151
|
+
type: 'value',
|
|
152
|
+
value: initialValue,
|
|
153
|
+
})
|
|
145
154
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
146
155
|
})
|
|
147
156
|
await waitFor(() => {
|
|
@@ -210,7 +219,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
210
219
|
/>,
|
|
211
220
|
)
|
|
212
221
|
await waitFor(() => {
|
|
213
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
222
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
223
|
+
type: 'value',
|
|
224
|
+
value: initialValue,
|
|
225
|
+
})
|
|
214
226
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
215
227
|
})
|
|
216
228
|
await waitFor(() => {
|
|
@@ -271,7 +283,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
271
283
|
/>,
|
|
272
284
|
)
|
|
273
285
|
await waitFor(() => {
|
|
274
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
286
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
287
|
+
type: 'value',
|
|
288
|
+
value: initialValue,
|
|
289
|
+
})
|
|
275
290
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
276
291
|
})
|
|
277
292
|
await waitFor(() => {
|
|
@@ -297,59 +312,6 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
297
312
|
})
|
|
298
313
|
})
|
|
299
314
|
|
|
300
|
-
it('allows missing .markDefs', async () => {
|
|
301
|
-
const editorRef: RefObject<PortableTextEditor> = createRef()
|
|
302
|
-
const initialValue = [
|
|
303
|
-
{
|
|
304
|
-
_key: 'abc',
|
|
305
|
-
_type: 'myTestBlockType',
|
|
306
|
-
children: [
|
|
307
|
-
{
|
|
308
|
-
_key: 'def',
|
|
309
|
-
_type: 'span',
|
|
310
|
-
marks: [],
|
|
311
|
-
text: 'No markDefs',
|
|
312
|
-
},
|
|
313
|
-
],
|
|
314
|
-
style: 'normal',
|
|
315
|
-
},
|
|
316
|
-
]
|
|
317
|
-
|
|
318
|
-
const onChange = jest.fn()
|
|
319
|
-
render(
|
|
320
|
-
<PortableTextEditorTester
|
|
321
|
-
onChange={onChange}
|
|
322
|
-
ref={editorRef}
|
|
323
|
-
schemaType={schemaType}
|
|
324
|
-
value={initialValue}
|
|
325
|
-
/>,
|
|
326
|
-
)
|
|
327
|
-
await waitFor(() => {
|
|
328
|
-
expect(onChange).toHaveBeenCalledWith({type: 'value', value: initialValue})
|
|
329
|
-
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
330
|
-
})
|
|
331
|
-
await waitFor(() => {
|
|
332
|
-
if (editorRef.current) {
|
|
333
|
-
PortableTextEditor.focus(editorRef.current)
|
|
334
|
-
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
335
|
-
{
|
|
336
|
-
_key: 'abc',
|
|
337
|
-
_type: 'myTestBlockType',
|
|
338
|
-
children: [
|
|
339
|
-
{
|
|
340
|
-
_key: 'def',
|
|
341
|
-
_type: 'span',
|
|
342
|
-
text: 'No markDefs',
|
|
343
|
-
marks: [],
|
|
344
|
-
},
|
|
345
|
-
],
|
|
346
|
-
style: 'normal',
|
|
347
|
-
},
|
|
348
|
-
])
|
|
349
|
-
}
|
|
350
|
-
})
|
|
351
|
-
})
|
|
352
|
-
|
|
353
315
|
it('allows empty array of blocks', async () => {
|
|
354
316
|
const editorRef: RefObject<PortableTextEditor> = createRef()
|
|
355
317
|
const initialValue = [] as PortableTextBlock[]
|
|
@@ -364,7 +326,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
364
326
|
/>,
|
|
365
327
|
)
|
|
366
328
|
await waitFor(() => {
|
|
367
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
329
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
330
|
+
type: 'value',
|
|
331
|
+
value: initialValue,
|
|
332
|
+
})
|
|
368
333
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
369
334
|
})
|
|
370
335
|
await waitFor(() => {
|
|
@@ -382,7 +347,10 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
382
347
|
}
|
|
383
348
|
})
|
|
384
349
|
await waitFor(() => {
|
|
385
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
350
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
351
|
+
type: 'value',
|
|
352
|
+
value: initialValue,
|
|
353
|
+
})
|
|
386
354
|
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
387
355
|
})
|
|
388
356
|
})
|
|
@@ -3,7 +3,10 @@ import {fireEvent, type render} from '@testing-library/react'
|
|
|
3
3
|
import {parseHotkey} from 'is-hotkey-esm'
|
|
4
4
|
import {act} from 'react'
|
|
5
5
|
|
|
6
|
-
export async function triggerKeyboardEvent(
|
|
6
|
+
export async function triggerKeyboardEvent(
|
|
7
|
+
hotkey: string,
|
|
8
|
+
element: Element,
|
|
9
|
+
): Promise<void> {
|
|
7
10
|
const eventProps = parseHotkey(hotkey)
|
|
8
11
|
const values = hotkey.split('+')
|
|
9
12
|
|
|
@@ -19,9 +22,13 @@ export async function triggerKeyboardEvent(hotkey: string, element: Element): Pr
|
|
|
19
22
|
)
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
export async function getEditableElement(
|
|
25
|
+
export async function getEditableElement(
|
|
26
|
+
component: ReturnType<typeof render>,
|
|
27
|
+
): Promise<Element> {
|
|
23
28
|
await act(async () => component)
|
|
24
|
-
const element = component.container.querySelector(
|
|
29
|
+
const element = component.container.querySelector(
|
|
30
|
+
'[data-slate-editor="true"]',
|
|
31
|
+
)
|
|
25
32
|
if (!element) {
|
|
26
33
|
throw new Error('Could not find element')
|
|
27
34
|
}
|
|
@@ -31,7 +38,6 @@ export async function getEditableElement(component: ReturnType<typeof render>):
|
|
|
31
38
|
*
|
|
32
39
|
* https://github.com/jsdom/jsdom/issues/1670
|
|
33
40
|
*/
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
35
41
|
// @ts-ignore
|
|
36
42
|
element.isContentEditable = true
|
|
37
43
|
return element
|