@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,16 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type DragEvent,
|
|
3
|
-
type MutableRefObject,
|
|
4
|
-
type ReactNode,
|
|
5
2
|
useCallback,
|
|
6
3
|
useEffect,
|
|
7
4
|
useMemo,
|
|
8
5
|
useRef,
|
|
9
6
|
useState,
|
|
7
|
+
type DragEvent,
|
|
8
|
+
type MutableRefObject,
|
|
9
|
+
type ReactNode,
|
|
10
10
|
} from 'react'
|
|
11
|
-
import {Editor, type Element as SlateElement
|
|
11
|
+
import {Editor, Path, Transforms, type Element as SlateElement} from 'slate'
|
|
12
12
|
import {ReactEditor, useSlateStatic} from 'slate-react'
|
|
13
|
-
|
|
14
13
|
import {debugWithName} from '../../utils/debug'
|
|
15
14
|
import {
|
|
16
15
|
IS_DRAGGING,
|
|
@@ -36,17 +35,31 @@ export interface DraggableBlockProps {
|
|
|
36
35
|
* Implements drag and drop functionality on editor block nodes
|
|
37
36
|
* @internal
|
|
38
37
|
*/
|
|
39
|
-
export const DraggableBlock = ({
|
|
38
|
+
export const DraggableBlock = ({
|
|
39
|
+
children,
|
|
40
|
+
element,
|
|
41
|
+
readOnly,
|
|
42
|
+
blockRef,
|
|
43
|
+
}: DraggableBlockProps) => {
|
|
40
44
|
const editor = useSlateStatic()
|
|
41
45
|
const dragGhostRef: MutableRefObject<undefined | HTMLElement> = useRef()
|
|
42
46
|
const [isDragOver, setIsDragOver] = useState(false)
|
|
43
|
-
const isVoid = useMemo(
|
|
44
|
-
|
|
47
|
+
const isVoid = useMemo(
|
|
48
|
+
() => Editor.isVoid(editor, element),
|
|
49
|
+
[editor, element],
|
|
50
|
+
)
|
|
51
|
+
const isInline = useMemo(
|
|
52
|
+
() => Editor.isInline(editor, element),
|
|
53
|
+
[editor, element],
|
|
54
|
+
)
|
|
45
55
|
|
|
46
56
|
const [blockElement, setBlockElement] = useState<HTMLElement | null>(null)
|
|
47
57
|
|
|
48
58
|
useEffect(
|
|
49
|
-
() =>
|
|
59
|
+
() =>
|
|
60
|
+
setBlockElement(
|
|
61
|
+
blockRef ? blockRef.current : ReactEditor.toDOMNode(editor, element),
|
|
62
|
+
),
|
|
50
63
|
[editor, element, blockRef],
|
|
51
64
|
)
|
|
52
65
|
|
|
@@ -122,7 +135,11 @@ export const DraggableBlock = ({children, element, readOnly, blockRef}: Draggabl
|
|
|
122
135
|
)}`,
|
|
123
136
|
)
|
|
124
137
|
}
|
|
125
|
-
if (
|
|
138
|
+
if (
|
|
139
|
+
dragPosition === 'top' &&
|
|
140
|
+
isBefore &&
|
|
141
|
+
targetPath[0] !== editor.children.length - 1
|
|
142
|
+
) {
|
|
126
143
|
const originalPath = targetPath
|
|
127
144
|
targetPath = Path.previous(targetPath)
|
|
128
145
|
debug(
|
|
@@ -201,7 +218,9 @@ export const DraggableBlock = ({children, element, readOnly, blockRef}: Draggabl
|
|
|
201
218
|
// drag ghost by adding a truthy data attribute 'data-pt-drag-ghost-element' to a HTML element.
|
|
202
219
|
if (blockElement && blockElement instanceof HTMLElement) {
|
|
203
220
|
let dragGhost = blockElement.cloneNode(true) as HTMLElement
|
|
204
|
-
const customGhost = dragGhost.querySelector(
|
|
221
|
+
const customGhost = dragGhost.querySelector(
|
|
222
|
+
'[data-pt-drag-ghost-element]',
|
|
223
|
+
)
|
|
205
224
|
if (customGhost) {
|
|
206
225
|
dragGhost = customGhost as HTMLElement
|
|
207
226
|
}
|
|
@@ -232,12 +251,16 @@ export const DraggableBlock = ({children, element, readOnly, blockRef}: Draggabl
|
|
|
232
251
|
isDragOver && editor.children[0] === IS_DRAGGING_ELEMENT_TARGET.get(editor)
|
|
233
252
|
const isDraggingOverLastBlock =
|
|
234
253
|
isDragOver &&
|
|
235
|
-
editor.children[editor.children.length - 1] ===
|
|
254
|
+
editor.children[editor.children.length - 1] ===
|
|
255
|
+
IS_DRAGGING_ELEMENT_TARGET.get(editor)
|
|
236
256
|
const dragPosition = IS_DRAGGING_BLOCK_TARGET_POSITION.get(editor)
|
|
237
257
|
|
|
238
258
|
const isDraggingOverTop =
|
|
239
259
|
isDraggingOverFirstBlock ||
|
|
240
|
-
(isDragOver &&
|
|
260
|
+
(isDragOver &&
|
|
261
|
+
!isDraggingOverFirstBlock &&
|
|
262
|
+
!isDraggingOverLastBlock &&
|
|
263
|
+
dragPosition === 'top')
|
|
241
264
|
const isDraggingOverBottom =
|
|
242
265
|
isDraggingOverLastBlock ||
|
|
243
266
|
(isDragOver &&
|
|
@@ -1,28 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
type PortableTextObject,
|
|
7
|
-
type PortableTextTextBlock,
|
|
1
|
+
import type {
|
|
2
|
+
Path,
|
|
3
|
+
PortableTextChild,
|
|
4
|
+
PortableTextObject,
|
|
5
|
+
PortableTextTextBlock,
|
|
8
6
|
} from '@sanity/types'
|
|
9
|
-
import {type FunctionComponent, type ReactElement
|
|
10
|
-
import {Editor, Element as SlateElement
|
|
11
|
-
import {ReactEditor, type RenderElementProps, useSelected, useSlateStatic} from 'slate-react'
|
|
12
|
-
|
|
7
|
+
import {useMemo, useRef, type FunctionComponent, type ReactElement} from 'react'
|
|
8
|
+
import {Editor, Range, Element as SlateElement} from 'slate'
|
|
13
9
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
type
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
ReactEditor,
|
|
11
|
+
useSelected,
|
|
12
|
+
useSlateStatic,
|
|
13
|
+
type RenderElementProps,
|
|
14
|
+
} from 'slate-react'
|
|
15
|
+
import type {
|
|
16
|
+
BlockRenderProps,
|
|
17
|
+
PortableTextMemberSchemaTypes,
|
|
18
|
+
RenderBlockFunction,
|
|
19
|
+
RenderChildFunction,
|
|
20
|
+
RenderListItemFunction,
|
|
21
|
+
RenderStyleFunction,
|
|
20
22
|
} from '../../types/editor'
|
|
21
23
|
import {debugWithName} from '../../utils/debug'
|
|
22
24
|
import {fromSlateValue} from '../../utils/values'
|
|
23
25
|
import {KEY_TO_VALUE_ELEMENT} from '../../utils/weakMaps'
|
|
24
26
|
import ObjectNode from '../nodes/DefaultObject'
|
|
25
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
DefaultBlockObject,
|
|
29
|
+
DefaultListItem,
|
|
30
|
+
DefaultListItemInner,
|
|
31
|
+
} from '../nodes/index'
|
|
26
32
|
import {DraggableBlock} from './DraggableBlock'
|
|
27
33
|
|
|
28
34
|
const debug = debugWithName('components:Element')
|
|
@@ -67,16 +73,23 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
67
73
|
const selected = useSelected()
|
|
68
74
|
const blockRef = useRef<HTMLDivElement | null>(null)
|
|
69
75
|
const inlineBlockObjectRef = useRef(null)
|
|
70
|
-
const focused =
|
|
76
|
+
const focused =
|
|
77
|
+
(selected && editor.selection && Range.isCollapsed(editor.selection)) ||
|
|
78
|
+
false
|
|
71
79
|
|
|
72
80
|
const value = useMemo(
|
|
73
|
-
() =>
|
|
81
|
+
() =>
|
|
82
|
+
fromSlateValue(
|
|
83
|
+
[element],
|
|
84
|
+
schemaTypes.block.name,
|
|
85
|
+
KEY_TO_VALUE_ELEMENT.get(editor),
|
|
86
|
+
)[0],
|
|
74
87
|
[editor, element, schemaTypes.block.name],
|
|
75
88
|
)
|
|
76
89
|
|
|
77
90
|
let renderedBlock = children
|
|
78
91
|
|
|
79
|
-
let className
|
|
92
|
+
let className: string | undefined
|
|
80
93
|
|
|
81
94
|
const blockPath: Path = useMemo(() => [{_key: element._key}], [element])
|
|
82
95
|
|
|
@@ -92,12 +105,18 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
92
105
|
if (editor.isInline(element)) {
|
|
93
106
|
const path = ReactEditor.findPath(editor, element)
|
|
94
107
|
const [block] = Editor.node(editor, path, {depth: 1})
|
|
95
|
-
const schemaType = schemaTypes.inlineObjects.find(
|
|
108
|
+
const schemaType = schemaTypes.inlineObjects.find(
|
|
109
|
+
(_type) => _type.name === element._type,
|
|
110
|
+
)
|
|
96
111
|
if (!schemaType) {
|
|
97
112
|
throw new Error('Could not find type for inline block element')
|
|
98
113
|
}
|
|
99
114
|
if (SlateElement.isElement(block)) {
|
|
100
|
-
const elmPath: Path = [
|
|
115
|
+
const elmPath: Path = [
|
|
116
|
+
{_key: block._key},
|
|
117
|
+
'children',
|
|
118
|
+
{_key: element._key},
|
|
119
|
+
]
|
|
101
120
|
if (debugRenders) {
|
|
102
121
|
debug(`Render ${element._key} (inline object)`)
|
|
103
122
|
}
|
|
@@ -144,7 +163,9 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
144
163
|
}
|
|
145
164
|
const style = ('style' in element && element.style) || 'normal'
|
|
146
165
|
className = `pt-block pt-text-block pt-text-block-style-${style}`
|
|
147
|
-
const blockStyleType = schemaTypes.styles.find(
|
|
166
|
+
const blockStyleType = schemaTypes.styles.find(
|
|
167
|
+
(item) => item.value === style,
|
|
168
|
+
)
|
|
148
169
|
if (renderStyle && blockStyleType) {
|
|
149
170
|
renderedBlock = renderStyle({
|
|
150
171
|
block: element as PortableTextTextBlock,
|
|
@@ -157,7 +178,7 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
157
178
|
editorElementRef: blockRef,
|
|
158
179
|
})
|
|
159
180
|
}
|
|
160
|
-
let level
|
|
181
|
+
let level: number | undefined
|
|
161
182
|
if (isListItem) {
|
|
162
183
|
if (typeof element.level === 'number') {
|
|
163
184
|
level = element.level
|
|
@@ -165,7 +186,9 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
165
186
|
className += ` pt-list-item pt-list-item-${element.listItem} pt-list-item-level-${level || 1}`
|
|
166
187
|
}
|
|
167
188
|
if (editor.isListBlock(value) && isListItem && element.listItem) {
|
|
168
|
-
const listType = schemaTypes.lists.find(
|
|
189
|
+
const listType = schemaTypes.lists.find(
|
|
190
|
+
(item) => item.value === element.listItem,
|
|
191
|
+
)
|
|
169
192
|
if (renderListItem && listType) {
|
|
170
193
|
renderedBlock = renderListItem({
|
|
171
194
|
block: value,
|
|
@@ -206,7 +229,9 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
206
229
|
{
|
|
207
230
|
enumerable: false,
|
|
208
231
|
get() {
|
|
209
|
-
console.warn(
|
|
232
|
+
console.warn(
|
|
233
|
+
"Property 'type' is deprecated, use 'schemaType' instead.",
|
|
234
|
+
)
|
|
210
235
|
return schemaTypes.block
|
|
211
236
|
},
|
|
212
237
|
},
|
|
@@ -216,16 +241,29 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
216
241
|
? renderBlock(renderProps as BlockRenderProps)
|
|
217
242
|
: children
|
|
218
243
|
return (
|
|
219
|
-
<div
|
|
220
|
-
|
|
244
|
+
<div
|
|
245
|
+
key={element._key}
|
|
246
|
+
{...attributes}
|
|
247
|
+
className={className}
|
|
248
|
+
spellCheck={spellCheck}
|
|
249
|
+
>
|
|
250
|
+
<DraggableBlock
|
|
251
|
+
element={element}
|
|
252
|
+
readOnly={readOnly}
|
|
253
|
+
blockRef={blockRef}
|
|
254
|
+
>
|
|
221
255
|
<div ref={blockRef}>{propsOrDefaultRendered}</div>
|
|
222
256
|
</DraggableBlock>
|
|
223
257
|
</div>
|
|
224
258
|
)
|
|
225
259
|
}
|
|
226
|
-
const schemaType = schemaTypes.blockObjects.find(
|
|
260
|
+
const schemaType = schemaTypes.blockObjects.find(
|
|
261
|
+
(_type) => _type.name === element._type,
|
|
262
|
+
)
|
|
227
263
|
if (!schemaType) {
|
|
228
|
-
throw new Error(
|
|
264
|
+
throw new Error(
|
|
265
|
+
`Could not find schema type for block element of _type ${element._type}`,
|
|
266
|
+
)
|
|
229
267
|
}
|
|
230
268
|
if (debugRenders) {
|
|
231
269
|
debug(`Render ${element._key} (object block)`)
|
|
@@ -236,7 +274,7 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
236
274
|
schemaTypes.block.name,
|
|
237
275
|
KEY_TO_VALUE_ELEMENT.get(editor),
|
|
238
276
|
)[0]
|
|
239
|
-
let renderedBlockFromProps
|
|
277
|
+
let renderedBlockFromProps: JSX.Element | undefined
|
|
240
278
|
if (renderBlock) {
|
|
241
279
|
const _props: Omit<BlockRenderProps, 'type'> = Object.defineProperty(
|
|
242
280
|
{
|
|
@@ -252,7 +290,9 @@ export const Element: FunctionComponent<ElementProps> = ({
|
|
|
252
290
|
{
|
|
253
291
|
enumerable: false,
|
|
254
292
|
get() {
|
|
255
|
-
console.warn(
|
|
293
|
+
console.warn(
|
|
294
|
+
"Property 'type' is deprecated, use 'schemaType' instead.",
|
|
295
|
+
)
|
|
256
296
|
return schemaType
|
|
257
297
|
},
|
|
258
298
|
},
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type {
|
|
2
|
+
Path,
|
|
3
|
+
PortableTextObject,
|
|
4
|
+
PortableTextTextBlock,
|
|
5
|
+
} from '@sanity/types'
|
|
2
6
|
import {isEqual, uniq} from 'lodash'
|
|
3
7
|
import {
|
|
4
|
-
type ReactElement,
|
|
5
8
|
startTransition,
|
|
6
9
|
useCallback,
|
|
7
10
|
useEffect,
|
|
8
11
|
useMemo,
|
|
9
12
|
useRef,
|
|
10
13
|
useState,
|
|
14
|
+
type ReactElement,
|
|
11
15
|
} from 'react'
|
|
12
16
|
import {Text} from 'slate'
|
|
13
|
-
import {type RenderLeafProps
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type RenderDecoratorFunction,
|
|
17
|
+
import {useSelected, type RenderLeafProps} from 'slate-react'
|
|
18
|
+
import type {
|
|
19
|
+
BlockAnnotationRenderProps,
|
|
20
|
+
BlockChildRenderProps,
|
|
21
|
+
BlockDecoratorRenderProps,
|
|
22
|
+
PortableTextMemberSchemaTypes,
|
|
23
|
+
RenderAnnotationFunction,
|
|
24
|
+
RenderChildFunction,
|
|
25
|
+
RenderDecoratorFunction,
|
|
23
26
|
} from '../../types/editor'
|
|
24
27
|
import {debugWithName} from '../../utils/debug'
|
|
25
28
|
import {usePortableTextEditor} from '../hooks/usePortableTextEditor'
|
|
@@ -47,8 +50,15 @@ export interface LeafProps extends RenderLeafProps {
|
|
|
47
50
|
* @internal
|
|
48
51
|
*/
|
|
49
52
|
export const Leaf = (props: LeafProps) => {
|
|
50
|
-
const {
|
|
51
|
-
|
|
53
|
+
const {
|
|
54
|
+
attributes,
|
|
55
|
+
children,
|
|
56
|
+
leaf,
|
|
57
|
+
schemaTypes,
|
|
58
|
+
renderChild,
|
|
59
|
+
renderDecorator,
|
|
60
|
+
renderAnnotation,
|
|
61
|
+
} = props
|
|
52
62
|
const spanRef = useRef<HTMLElement>(null)
|
|
53
63
|
const portableTextEditor = usePortableTextEditor()
|
|
54
64
|
const blockSelected = useSelected()
|
|
@@ -64,7 +74,12 @@ export const Leaf = (props: LeafProps) => {
|
|
|
64
74
|
[schemaTypes.decorators],
|
|
65
75
|
)
|
|
66
76
|
const marks: string[] = useMemo(
|
|
67
|
-
() =>
|
|
77
|
+
() =>
|
|
78
|
+
uniq(
|
|
79
|
+
(leaf.marks || EMPTY_MARKS).filter((mark) =>
|
|
80
|
+
decoratorValues.includes(mark),
|
|
81
|
+
),
|
|
82
|
+
),
|
|
68
83
|
[decoratorValues, leaf.marks],
|
|
69
84
|
)
|
|
70
85
|
const annotationMarks = Array.isArray(leaf.marks) ? leaf.marks : EMPTY_MARKS
|
|
@@ -73,7 +88,8 @@ export const Leaf = (props: LeafProps) => {
|
|
|
73
88
|
annotationMarks
|
|
74
89
|
.map(
|
|
75
90
|
(mark) =>
|
|
76
|
-
!decoratorValues.includes(mark) &&
|
|
91
|
+
!decoratorValues.includes(mark) &&
|
|
92
|
+
block?.markDefs?.find((def) => def._key === mark),
|
|
77
93
|
)
|
|
78
94
|
.filter(Boolean) as PortableTextObject[],
|
|
79
95
|
[annotationMarks, block, decoratorValues],
|
|
@@ -159,7 +175,12 @@ export const Leaf = (props: LeafProps) => {
|
|
|
159
175
|
return () => {
|
|
160
176
|
sub.unsubscribe()
|
|
161
177
|
}
|
|
162
|
-
}, [
|
|
178
|
+
}, [
|
|
179
|
+
path,
|
|
180
|
+
portableTextEditor,
|
|
181
|
+
setSelectedFromRange,
|
|
182
|
+
shouldTrackSelectionAndFocus,
|
|
183
|
+
])
|
|
163
184
|
|
|
164
185
|
useEffect(() => setSelectedFromRange(), [setSelectedFromRange])
|
|
165
186
|
|
|
@@ -168,59 +189,73 @@ export const Leaf = (props: LeafProps) => {
|
|
|
168
189
|
// Render text nodes
|
|
169
190
|
if (Text.isText(leaf) && leaf._type === schemaTypes.span.name) {
|
|
170
191
|
marks.forEach((mark) => {
|
|
171
|
-
const schemaType = schemaTypes.decorators.find(
|
|
192
|
+
const schemaType = schemaTypes.decorators.find(
|
|
193
|
+
(dec) => dec.value === mark,
|
|
194
|
+
)
|
|
172
195
|
if (schemaType && renderDecorator) {
|
|
173
|
-
const _props: Omit<BlockDecoratorRenderProps, 'type'> =
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
196
|
+
const _props: Omit<BlockDecoratorRenderProps, 'type'> =
|
|
197
|
+
Object.defineProperty(
|
|
198
|
+
{
|
|
199
|
+
children: returnedChildren,
|
|
200
|
+
editorElementRef: spanRef,
|
|
201
|
+
focused,
|
|
202
|
+
path,
|
|
203
|
+
selected,
|
|
204
|
+
schemaType,
|
|
205
|
+
value: mark,
|
|
206
|
+
},
|
|
207
|
+
'type',
|
|
208
|
+
{
|
|
209
|
+
enumerable: false,
|
|
210
|
+
get() {
|
|
211
|
+
console.warn(
|
|
212
|
+
"Property 'type' is deprecated, use 'schemaType' instead.",
|
|
213
|
+
)
|
|
214
|
+
return schemaType
|
|
215
|
+
},
|
|
189
216
|
},
|
|
190
|
-
|
|
217
|
+
)
|
|
218
|
+
returnedChildren = renderDecorator(
|
|
219
|
+
_props as BlockDecoratorRenderProps,
|
|
191
220
|
)
|
|
192
|
-
returnedChildren = renderDecorator(_props as BlockDecoratorRenderProps)
|
|
193
221
|
}
|
|
194
222
|
})
|
|
195
223
|
|
|
196
224
|
if (block && annotations.length > 0) {
|
|
197
225
|
annotations.forEach((annotation) => {
|
|
198
|
-
const schemaType = schemaTypes.annotations.find(
|
|
226
|
+
const schemaType = schemaTypes.annotations.find(
|
|
227
|
+
(t) => t.name === annotation._type,
|
|
228
|
+
)
|
|
199
229
|
if (schemaType) {
|
|
200
230
|
if (renderAnnotation) {
|
|
201
|
-
const _props: Omit<BlockAnnotationRenderProps, 'type'> =
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
'type',
|
|
213
|
-
{
|
|
214
|
-
enumerable: false,
|
|
215
|
-
get() {
|
|
216
|
-
console.warn("Property 'type' is deprecated, use 'schemaType' instead.")
|
|
217
|
-
return schemaType
|
|
231
|
+
const _props: Omit<BlockAnnotationRenderProps, 'type'> =
|
|
232
|
+
Object.defineProperty(
|
|
233
|
+
{
|
|
234
|
+
block,
|
|
235
|
+
children: returnedChildren,
|
|
236
|
+
editorElementRef: spanRef,
|
|
237
|
+
focused,
|
|
238
|
+
path,
|
|
239
|
+
selected,
|
|
240
|
+
schemaType,
|
|
241
|
+
value: annotation,
|
|
218
242
|
},
|
|
219
|
-
|
|
220
|
-
|
|
243
|
+
'type',
|
|
244
|
+
{
|
|
245
|
+
enumerable: false,
|
|
246
|
+
get() {
|
|
247
|
+
console.warn(
|
|
248
|
+
"Property 'type' is deprecated, use 'schemaType' instead.",
|
|
249
|
+
)
|
|
250
|
+
return schemaType
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
)
|
|
221
254
|
|
|
222
255
|
returnedChildren = (
|
|
223
|
-
<span ref={spanRef}>
|
|
256
|
+
<span ref={spanRef}>
|
|
257
|
+
{renderAnnotation(_props as BlockAnnotationRenderProps)}
|
|
258
|
+
</span>
|
|
224
259
|
)
|
|
225
260
|
} else {
|
|
226
261
|
returnedChildren = (
|
|
@@ -236,26 +271,29 @@ export const Leaf = (props: LeafProps) => {
|
|
|
236
271
|
const child = block.children.find((_child) => _child._key === leaf._key) // Ensure object equality
|
|
237
272
|
if (child) {
|
|
238
273
|
const defaultRendered = <>{returnedChildren}</>
|
|
239
|
-
const _props: Omit<BlockChildRenderProps, 'type'> =
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
'type',
|
|
251
|
-
{
|
|
252
|
-
enumerable: false,
|
|
253
|
-
get() {
|
|
254
|
-
console.warn("Property 'type' is deprecated, use 'schemaType' instead.")
|
|
255
|
-
return schemaTypes.span
|
|
274
|
+
const _props: Omit<BlockChildRenderProps, 'type'> =
|
|
275
|
+
Object.defineProperty(
|
|
276
|
+
{
|
|
277
|
+
annotations,
|
|
278
|
+
children: defaultRendered,
|
|
279
|
+
editorElementRef: spanRef,
|
|
280
|
+
focused,
|
|
281
|
+
path,
|
|
282
|
+
schemaType: schemaTypes.span,
|
|
283
|
+
selected,
|
|
284
|
+
value: child,
|
|
256
285
|
},
|
|
257
|
-
|
|
258
|
-
|
|
286
|
+
'type',
|
|
287
|
+
{
|
|
288
|
+
enumerable: false,
|
|
289
|
+
get() {
|
|
290
|
+
console.warn(
|
|
291
|
+
"Property 'type' is deprecated, use 'schemaType' instead.",
|
|
292
|
+
)
|
|
293
|
+
return schemaTypes.span
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
)
|
|
259
297
|
returnedChildren = renderChild(_props as BlockChildRenderProps)
|
|
260
298
|
}
|
|
261
299
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {useEffect, useMemo, useState, type PropsWithChildren} from 'react'
|
|
2
2
|
import {createEditor} from 'slate'
|
|
3
3
|
import {Slate, withReact} from 'slate-react'
|
|
4
|
-
|
|
5
|
-
import {type PatchObservable} from '../../types/editor'
|
|
4
|
+
import type {PatchObservable} from '../../types/editor'
|
|
6
5
|
import {debugWithName} from '../../utils/debug'
|
|
7
6
|
import {KEY_TO_SLATE_ELEMENT, KEY_TO_VALUE_ELEMENT} from '../../utils/weakMaps'
|
|
8
7
|
import {withPlugins} from '../plugins'
|
|
9
|
-
import
|
|
8
|
+
import type {PortableTextEditor} from '../PortableTextEditor'
|
|
10
9
|
|
|
11
10
|
const debug = debugWithName('component:PortableTextEditor:SlateContainer')
|
|
12
11
|
|
|
@@ -26,7 +25,8 @@ export interface SlateContainerProps extends PropsWithChildren {
|
|
|
26
25
|
* @internal
|
|
27
26
|
*/
|
|
28
27
|
export function SlateContainer(props: SlateContainerProps) {
|
|
29
|
-
const {patches$, portableTextEditor, readOnly, maxBlocks, keyGenerator} =
|
|
28
|
+
const {patches$, portableTextEditor, readOnly, maxBlocks, keyGenerator} =
|
|
29
|
+
props
|
|
30
30
|
|
|
31
31
|
// Create the slate instance, using `useState` ensures setup is only run once, initially
|
|
32
32
|
const [[slateEditor, subscribe]] = useState(() => {
|
|
@@ -60,10 +60,17 @@ export function SlateContainer(props: SlateContainerProps) {
|
|
|
60
60
|
portableTextEditor,
|
|
61
61
|
readOnly,
|
|
62
62
|
})
|
|
63
|
-
}, [
|
|
63
|
+
}, [
|
|
64
|
+
keyGenerator,
|
|
65
|
+
portableTextEditor,
|
|
66
|
+
maxBlocks,
|
|
67
|
+
readOnly,
|
|
68
|
+
patches$,
|
|
69
|
+
slateEditor,
|
|
70
|
+
])
|
|
64
71
|
|
|
65
72
|
const initialValue = useMemo(() => {
|
|
66
|
-
return [slateEditor.
|
|
73
|
+
return [slateEditor.pteCreateTextBlock({decorators: []})]
|
|
67
74
|
}, [slateEditor])
|
|
68
75
|
|
|
69
76
|
useEffect(() => {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import type {Patch} from '@portabletext/patches'
|
|
2
|
+
import type {PortableTextBlock} from '@sanity/types'
|
|
3
3
|
import {throttle} from 'lodash'
|
|
4
4
|
import {useCallback, useEffect, useMemo, useRef} from 'react'
|
|
5
5
|
import {Editor} from 'slate'
|
|
6
6
|
import {useSlate} from 'slate-react'
|
|
7
|
-
|
|
8
|
-
import {type EditorChange, type EditorChanges} from '../../types/editor'
|
|
7
|
+
import type {EditorChange, EditorChanges} from '../../types/editor'
|
|
9
8
|
import {debugWithName} from '../../utils/debug'
|
|
10
9
|
import {IS_PROCESSING_LOCAL_CHANGES} from '../../utils/weakMaps'
|
|
11
10
|
import {usePortableTextEditor} from '../hooks/usePortableTextEditor'
|
|
@@ -61,7 +60,11 @@ export function Synchronizer(props: SynchronizerProps) {
|
|
|
61
60
|
debug(`Patches:\n${JSON.stringify(pendingPatches.current, null, 2)}`)
|
|
62
61
|
}
|
|
63
62
|
const snapshot = getValue()
|
|
64
|
-
change$.next({
|
|
63
|
+
change$.next({
|
|
64
|
+
type: 'mutation',
|
|
65
|
+
patches: pendingPatches.current,
|
|
66
|
+
snapshot,
|
|
67
|
+
})
|
|
65
68
|
pendingPatches.current = []
|
|
66
69
|
}
|
|
67
70
|
IS_PROCESSING_LOCAL_CHANGES.set(slateEditor, false)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {createContext, useContext} from 'react'
|
|
2
|
-
|
|
3
|
-
import {type PortableTextEditor} from '../PortableTextEditor'
|
|
2
|
+
import type {PortableTextEditor} from '../PortableTextEditor'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* A React context for sharing the editor object.
|
|
7
6
|
*/
|
|
8
|
-
export const PortableTextEditorContext =
|
|
7
|
+
export const PortableTextEditorContext =
|
|
8
|
+
createContext<PortableTextEditor | null>(null)
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @public
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
startTransition,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react'
|
|
8
|
+
import type {EditorChanges, EditorSelection} from '../../types/editor'
|
|
4
9
|
import {debugWithName} from '../../utils/debug'
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* A React context for sharing the editor selection.
|
|
8
13
|
*/
|
|
9
|
-
const PortableTextEditorSelectionContext =
|
|
14
|
+
const PortableTextEditorSelectionContext =
|
|
15
|
+
createContext<EditorSelection | null>(null)
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* @public
|