@portabletext/editor 1.48.15 → 1.49.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/_chunks-cjs/editor-provider.cjs +32 -17
- package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
- package/lib/_chunks-cjs/util.slice-blocks.cjs +2 -0
- package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
- package/lib/_chunks-es/editor-provider.js +32 -17
- package/lib/_chunks-es/editor-provider.js.map +1 -1
- package/lib/_chunks-es/util.slice-blocks.js +2 -0
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
- package/lib/index.cjs +360 -294
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +367 -301
- package/lib/index.js.map +1 -1
- package/package.json +7 -7
- package/src/behaviors/behavior.core.block-element.ts +108 -0
- package/src/converters/converter.portable-text.ts +4 -1
- package/src/converters/converter.text-html.ts +4 -1
- package/src/converters/converter.text-plain.ts +4 -1
- package/src/editor/Editable.tsx +21 -52
- package/src/editor/__tests__/PortableTextEditor.test.tsx +6 -0
- package/src/editor/__tests__/RangeDecorations.test.tsx +2 -2
- package/src/editor/components/render-block-object.tsx +89 -0
- package/src/editor/components/render-default-object.tsx +21 -0
- package/src/editor/components/render-element.tsx +140 -0
- package/src/editor/components/render-inline-object.tsx +90 -0
- package/src/editor/components/render-leaf.tsx +64 -0
- package/src/editor/components/render-span.tsx +260 -0
- package/src/editor/components/render-text-block.tsx +147 -0
- package/src/editor/components/render-text.tsx +18 -0
- package/src/editor/components/use-core-block-element-behaviors.ts +39 -0
- package/src/internal-utils/parse-blocks.ts +2 -2
- package/src/internal-utils/slate-utils.ts +1 -1
- package/src/editor/components/DefaultObject.tsx +0 -21
- package/src/editor/components/Element.tsx +0 -461
- package/src/editor/components/Leaf.tsx +0 -329
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.49.1",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -79,15 +79,15 @@
|
|
|
79
79
|
"slate-react": "0.114.2",
|
|
80
80
|
"use-effect-event": "^1.0.2",
|
|
81
81
|
"xstate": "^5.19.2",
|
|
82
|
-
"@portabletext/
|
|
83
|
-
"@portabletext/
|
|
82
|
+
"@portabletext/patches": "1.1.3",
|
|
83
|
+
"@portabletext/block-tools": "1.1.24"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@portabletext/toolkit": "^2.0.17",
|
|
87
87
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
88
88
|
"@sanity/pkg-utils": "^7.2.2",
|
|
89
|
-
"@sanity/schema": "^3.
|
|
90
|
-
"@sanity/types": "^3.
|
|
89
|
+
"@sanity/schema": "^3.88.0",
|
|
90
|
+
"@sanity/types": "^3.88.0",
|
|
91
91
|
"@testing-library/jest-dom": "^6.6.3",
|
|
92
92
|
"@testing-library/react": "^16.3.0",
|
|
93
93
|
"@types/debug": "^4.1.12",
|
|
@@ -114,8 +114,8 @@
|
|
|
114
114
|
"racejar": "1.2.4"
|
|
115
115
|
},
|
|
116
116
|
"peerDependencies": {
|
|
117
|
-
"@sanity/schema": "^3.
|
|
118
|
-
"@sanity/types": "^3.
|
|
117
|
+
"@sanity/schema": "^3.88.0",
|
|
118
|
+
"@sanity/types": "^3.88.0",
|
|
119
119
|
"react": "^16.9 || ^17 || ^18 || ^19",
|
|
120
120
|
"rxjs": "^7.8.2"
|
|
121
121
|
},
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type {EventPositionBlock} from '../internal-utils/event-position'
|
|
2
|
+
import {corePriority} from '../priority/priority.core'
|
|
3
|
+
import {createEditorPriority} from '../priority/priority.types'
|
|
4
|
+
import * as selectors from '../selectors'
|
|
5
|
+
import {forward} from './behavior.types.action'
|
|
6
|
+
import {defineBehavior} from './behavior.types.behavior'
|
|
7
|
+
|
|
8
|
+
export function createCoreBlockElementBehaviorsConfig({
|
|
9
|
+
key,
|
|
10
|
+
onSetDragPositionBlock,
|
|
11
|
+
}: {
|
|
12
|
+
key: string
|
|
13
|
+
onSetDragPositionBlock: (
|
|
14
|
+
eventPositionBlock: EventPositionBlock | undefined,
|
|
15
|
+
) => void
|
|
16
|
+
}) {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
behavior: defineBehavior({
|
|
20
|
+
on: 'drag.dragover',
|
|
21
|
+
guard: ({snapshot, event}) => {
|
|
22
|
+
const dropFocusBlock = selectors.getFocusBlock({
|
|
23
|
+
...snapshot,
|
|
24
|
+
context: {
|
|
25
|
+
...snapshot.context,
|
|
26
|
+
selection: event.position.selection,
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
if (!dropFocusBlock || dropFocusBlock.node._key !== key) {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const dragOrigin = snapshot.beta.internalDrag?.origin
|
|
35
|
+
|
|
36
|
+
if (!dragOrigin) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const draggedBlocks = selectors.getSelectedBlocks({
|
|
41
|
+
...snapshot,
|
|
42
|
+
context: {
|
|
43
|
+
...snapshot.context,
|
|
44
|
+
selection: dragOrigin.selection,
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
draggedBlocks.some((draggedBlock) => draggedBlock.node._key === key)
|
|
50
|
+
) {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const draggingEntireBlocks = selectors.isSelectingEntireBlocks({
|
|
55
|
+
...snapshot,
|
|
56
|
+
context: {
|
|
57
|
+
...snapshot.context,
|
|
58
|
+
selection: dragOrigin.selection,
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return draggingEntireBlocks
|
|
63
|
+
},
|
|
64
|
+
actions: [
|
|
65
|
+
({event}) => [
|
|
66
|
+
{
|
|
67
|
+
type: 'effect',
|
|
68
|
+
effect: () => {
|
|
69
|
+
onSetDragPositionBlock(event.position.block)
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
],
|
|
74
|
+
}),
|
|
75
|
+
priority: createEditorPriority({
|
|
76
|
+
reference: {
|
|
77
|
+
priority: corePriority,
|
|
78
|
+
importance: 'lower',
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
behavior: defineBehavior({
|
|
84
|
+
on: 'drag.*',
|
|
85
|
+
guard: ({event}) => {
|
|
86
|
+
return event.type !== 'drag.dragover'
|
|
87
|
+
},
|
|
88
|
+
actions: [
|
|
89
|
+
({event}) => [
|
|
90
|
+
{
|
|
91
|
+
type: 'effect',
|
|
92
|
+
effect: () => {
|
|
93
|
+
onSetDragPositionBlock(undefined)
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
forward(event),
|
|
97
|
+
],
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
priority: createEditorPriority({
|
|
101
|
+
reference: {
|
|
102
|
+
priority: corePriority,
|
|
103
|
+
importance: 'lower',
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
},
|
|
107
|
+
]
|
|
108
|
+
}
|
package/src/editor/Editable.tsx
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
useRef,
|
|
11
11
|
useState,
|
|
12
12
|
type ClipboardEvent,
|
|
13
|
-
type CSSProperties,
|
|
14
13
|
type FocusEventHandler,
|
|
15
14
|
type KeyboardEvent,
|
|
16
15
|
type MutableRefObject,
|
|
@@ -53,8 +52,9 @@ import type {
|
|
|
53
52
|
import type {HotkeyOptions} from '../types/options'
|
|
54
53
|
import {isSelectionCollapsed} from '../utils'
|
|
55
54
|
import {getSelectionEndPoint} from '../utils/util.get-selection-end-point'
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
55
|
+
import {RenderElement} from './components/render-element'
|
|
56
|
+
import {RenderLeaf} from './components/render-leaf'
|
|
57
|
+
import {RenderText, type RenderTextProps} from './components/render-text'
|
|
58
58
|
import {EditorActorContext} from './editor-actor-context'
|
|
59
59
|
import {getEditorSnapshot} from './editor-selector'
|
|
60
60
|
import {usePortableTextEditor} from './hooks/usePortableTextEditor'
|
|
@@ -67,14 +67,6 @@ import {
|
|
|
67
67
|
|
|
68
68
|
const debug = debugWithName('component:Editable')
|
|
69
69
|
|
|
70
|
-
const PLACEHOLDER_STYLE: CSSProperties = {
|
|
71
|
-
position: 'absolute',
|
|
72
|
-
userSelect: 'none',
|
|
73
|
-
pointerEvents: 'none',
|
|
74
|
-
left: 0,
|
|
75
|
-
right: 0,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
70
|
/**
|
|
79
71
|
* @public
|
|
80
72
|
*/
|
|
@@ -223,19 +215,17 @@ export const PortableTextEditable = forwardRef<
|
|
|
223
215
|
|
|
224
216
|
const renderElement = useCallback(
|
|
225
217
|
(eProps: RenderElementProps) => (
|
|
226
|
-
<
|
|
218
|
+
<RenderElement
|
|
227
219
|
{...eProps}
|
|
228
220
|
readOnly={readOnly}
|
|
229
221
|
renderBlock={renderBlock}
|
|
230
222
|
renderChild={renderChild}
|
|
231
223
|
renderListItem={renderListItem}
|
|
232
224
|
renderStyle={renderStyle}
|
|
233
|
-
schemaTypes={portableTextEditor.schemaTypes}
|
|
234
225
|
spellCheck={spellCheck}
|
|
235
226
|
/>
|
|
236
227
|
),
|
|
237
228
|
[
|
|
238
|
-
portableTextEditor,
|
|
239
229
|
spellCheck,
|
|
240
230
|
readOnly,
|
|
241
231
|
renderBlock,
|
|
@@ -247,47 +237,20 @@ export const PortableTextEditable = forwardRef<
|
|
|
247
237
|
|
|
248
238
|
const renderLeaf = useCallback(
|
|
249
239
|
(
|
|
250
|
-
|
|
240
|
+
leafProps: RenderLeafProps & {
|
|
251
241
|
leaf: Text & {placeholder?: boolean; rangeDecoration?: RangeDecoration}
|
|
252
242
|
},
|
|
253
|
-
) =>
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
readOnly={readOnly}
|
|
264
|
-
/>
|
|
265
|
-
)
|
|
266
|
-
if (
|
|
267
|
-
renderPlaceholder &&
|
|
268
|
-
lProps.leaf.placeholder &&
|
|
269
|
-
lProps.text.text === ''
|
|
270
|
-
) {
|
|
271
|
-
return (
|
|
272
|
-
<>
|
|
273
|
-
<span style={PLACEHOLDER_STYLE} contentEditable={false}>
|
|
274
|
-
{renderPlaceholder()}
|
|
275
|
-
</span>
|
|
276
|
-
{rendered}
|
|
277
|
-
</>
|
|
278
|
-
)
|
|
279
|
-
}
|
|
280
|
-
const decoration = lProps.leaf.rangeDecoration
|
|
281
|
-
if (decoration) {
|
|
282
|
-
rendered = decoration.component({children: rendered})
|
|
283
|
-
}
|
|
284
|
-
return rendered
|
|
285
|
-
}
|
|
286
|
-
return lProps.children
|
|
287
|
-
},
|
|
243
|
+
) => (
|
|
244
|
+
<RenderLeaf
|
|
245
|
+
{...leafProps}
|
|
246
|
+
readOnly={readOnly}
|
|
247
|
+
renderAnnotation={renderAnnotation}
|
|
248
|
+
renderChild={renderChild}
|
|
249
|
+
renderDecorator={renderDecorator}
|
|
250
|
+
renderPlaceholder={renderPlaceholder}
|
|
251
|
+
/>
|
|
252
|
+
),
|
|
288
253
|
[
|
|
289
|
-
editorActor,
|
|
290
|
-
portableTextEditor,
|
|
291
254
|
readOnly,
|
|
292
255
|
renderAnnotation,
|
|
293
256
|
renderChild,
|
|
@@ -296,6 +259,11 @@ export const PortableTextEditable = forwardRef<
|
|
|
296
259
|
],
|
|
297
260
|
)
|
|
298
261
|
|
|
262
|
+
const renderText = useCallback(
|
|
263
|
+
(props: RenderTextProps) => <RenderText {...props} />,
|
|
264
|
+
[],
|
|
265
|
+
)
|
|
266
|
+
|
|
299
267
|
const restoreSelectionFromProps = useCallback(() => {
|
|
300
268
|
if (propsSelection) {
|
|
301
269
|
debug(`Selection from props ${JSON.stringify(propsSelection)}`)
|
|
@@ -1227,6 +1195,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1227
1195
|
renderPlaceholder={undefined}
|
|
1228
1196
|
renderElement={renderElement}
|
|
1229
1197
|
renderLeaf={renderLeaf}
|
|
1198
|
+
renderText={renderText}
|
|
1230
1199
|
scrollSelectionIntoView={scrollSelectionIntoViewToSlate}
|
|
1231
1200
|
/>
|
|
1232
1201
|
)
|
|
@@ -52,10 +52,16 @@ describe('initialization', () => {
|
|
|
52
52
|
>
|
|
53
53
|
<div
|
|
54
54
|
class="pt-block pt-text-block pt-text-block-style-normal"
|
|
55
|
+
data-block-key="k0"
|
|
56
|
+
data-block-name="myTestBlockType"
|
|
57
|
+
data-block-type="text"
|
|
55
58
|
data-slate-node="element"
|
|
56
59
|
>
|
|
57
60
|
<div>
|
|
58
61
|
<span
|
|
62
|
+
data-child-key="k1"
|
|
63
|
+
data-child-name="span"
|
|
64
|
+
data-child-type="span"
|
|
59
65
|
data-slate-node="text"
|
|
60
66
|
>
|
|
61
67
|
<span
|
|
@@ -125,7 +125,7 @@ describe('RangeDecorations', () => {
|
|
|
125
125
|
)
|
|
126
126
|
await waitFor(() => {
|
|
127
127
|
expect([rangeDecorationIteration, 'updated-with-different']).toEqual([
|
|
128
|
-
|
|
128
|
+
2,
|
|
129
129
|
'updated-with-different',
|
|
130
130
|
])
|
|
131
131
|
})
|
|
@@ -152,7 +152,7 @@ describe('RangeDecorations', () => {
|
|
|
152
152
|
)
|
|
153
153
|
await waitFor(() => {
|
|
154
154
|
expect([rangeDecorationIteration, 'updated-with-different']).toEqual([
|
|
155
|
-
|
|
155
|
+
3,
|
|
156
156
|
'updated-with-different',
|
|
157
157
|
])
|
|
158
158
|
})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type {PortableTextObject} from '@sanity/types'
|
|
2
|
+
import {useSelector} from '@xstate/react'
|
|
3
|
+
import {useContext, useRef, useState, type ReactElement} from 'react'
|
|
4
|
+
import {Range, type Element as SlateElement} from 'slate'
|
|
5
|
+
import {useSelected, useSlateStatic, type RenderElementProps} from 'slate-react'
|
|
6
|
+
import type {EventPositionBlock} from '../../internal-utils/event-position'
|
|
7
|
+
import type {RenderBlockFunction} from '../../types/editor'
|
|
8
|
+
import {EditorActorContext} from '../editor-actor-context'
|
|
9
|
+
import {DropIndicator} from './drop-indicator'
|
|
10
|
+
import {RenderDefaultBlockObject} from './render-default-object'
|
|
11
|
+
import {useCoreBlockElementBehaviors} from './use-core-block-element-behaviors'
|
|
12
|
+
|
|
13
|
+
export function RenderBlockObject(props: {
|
|
14
|
+
attributes: RenderElementProps['attributes']
|
|
15
|
+
blockObject: PortableTextObject
|
|
16
|
+
children: ReactElement
|
|
17
|
+
element: SlateElement
|
|
18
|
+
readOnly: boolean
|
|
19
|
+
renderBlock?: RenderBlockFunction
|
|
20
|
+
}) {
|
|
21
|
+
const [dragPositionBlock, setDragPositionBlock] =
|
|
22
|
+
useState<EventPositionBlock>()
|
|
23
|
+
const blockObjectRef = useRef<HTMLDivElement>(null)
|
|
24
|
+
|
|
25
|
+
const slateEditor = useSlateStatic()
|
|
26
|
+
const selected = useSelected()
|
|
27
|
+
|
|
28
|
+
const editorActor = useContext(EditorActorContext)
|
|
29
|
+
|
|
30
|
+
useCoreBlockElementBehaviors({
|
|
31
|
+
key: props.element._key,
|
|
32
|
+
onSetDragPositionBlock: setDragPositionBlock,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const legacySchemaType = useSelector(editorActor, (s) =>
|
|
36
|
+
s.context
|
|
37
|
+
.getLegacySchema()
|
|
38
|
+
.blockObjects.find(
|
|
39
|
+
(blockObject) => blockObject.name === props.element._type,
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if (!legacySchemaType) {
|
|
44
|
+
console.error(
|
|
45
|
+
`Block object type ${props.element._type} not found in Schema`,
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const focused =
|
|
50
|
+
selected &&
|
|
51
|
+
slateEditor.selection !== null &&
|
|
52
|
+
Range.isCollapsed(slateEditor.selection)
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
{...props.attributes}
|
|
57
|
+
className="pt-block pt-object-block"
|
|
58
|
+
data-block-key={props.element._key}
|
|
59
|
+
data-block-name={props.element._type}
|
|
60
|
+
data-block-type="object"
|
|
61
|
+
>
|
|
62
|
+
{dragPositionBlock === 'start' ? <DropIndicator /> : null}
|
|
63
|
+
{props.children}
|
|
64
|
+
<div
|
|
65
|
+
ref={blockObjectRef}
|
|
66
|
+
contentEditable={false}
|
|
67
|
+
draggable={!props.readOnly}
|
|
68
|
+
>
|
|
69
|
+
{props.renderBlock && legacySchemaType ? (
|
|
70
|
+
props.renderBlock({
|
|
71
|
+
children: (
|
|
72
|
+
<RenderDefaultBlockObject blockObject={props.blockObject} />
|
|
73
|
+
),
|
|
74
|
+
editorElementRef: blockObjectRef,
|
|
75
|
+
focused,
|
|
76
|
+
path: [{_key: props.element._key}],
|
|
77
|
+
schemaType: legacySchemaType,
|
|
78
|
+
selected,
|
|
79
|
+
type: legacySchemaType,
|
|
80
|
+
value: props.blockObject,
|
|
81
|
+
})
|
|
82
|
+
) : (
|
|
83
|
+
<RenderDefaultBlockObject blockObject={props.blockObject} />
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
{dragPositionBlock === 'end' ? <DropIndicator /> : null}
|
|
87
|
+
</div>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type {PortableTextChild, PortableTextObject} from '@sanity/types'
|
|
2
|
+
|
|
3
|
+
export function RenderDefaultBlockObject(props: {
|
|
4
|
+
blockObject: PortableTextObject
|
|
5
|
+
}) {
|
|
6
|
+
return (
|
|
7
|
+
<div style={{userSelect: 'none'}}>
|
|
8
|
+
[{props.blockObject._type}: {props.blockObject._key}]
|
|
9
|
+
</div>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function RenderDefaultInlineObject(props: {
|
|
14
|
+
inlineObject: PortableTextObject | PortableTextChild
|
|
15
|
+
}) {
|
|
16
|
+
return (
|
|
17
|
+
<span style={{userSelect: 'none'}}>
|
|
18
|
+
[{props.inlineObject._type}: {props.inlineObject._key}]
|
|
19
|
+
</span>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {useSelector} from '@xstate/react'
|
|
2
|
+
import {useContext, type ReactElement} from 'react'
|
|
3
|
+
import type {Element as SlateElement} from 'slate'
|
|
4
|
+
import type {RenderElementProps} from 'slate-react'
|
|
5
|
+
import {
|
|
6
|
+
parseBlockObject,
|
|
7
|
+
parseInlineObject,
|
|
8
|
+
parseTextBlock,
|
|
9
|
+
} from '../../internal-utils/parse-blocks'
|
|
10
|
+
import type {
|
|
11
|
+
RenderBlockFunction,
|
|
12
|
+
RenderChildFunction,
|
|
13
|
+
RenderListItemFunction,
|
|
14
|
+
RenderStyleFunction,
|
|
15
|
+
} from '../../types/editor'
|
|
16
|
+
import {EditorActorContext} from '../editor-actor-context'
|
|
17
|
+
import {RenderBlockObject} from './render-block-object'
|
|
18
|
+
import {RenderInlineObject} from './render-inline-object'
|
|
19
|
+
import {RenderTextBlock} from './render-text-block'
|
|
20
|
+
|
|
21
|
+
export function RenderElement(props: {
|
|
22
|
+
attributes: RenderElementProps['attributes']
|
|
23
|
+
children: ReactElement
|
|
24
|
+
element: SlateElement
|
|
25
|
+
readOnly: boolean
|
|
26
|
+
renderBlock?: RenderBlockFunction
|
|
27
|
+
renderChild?: RenderChildFunction
|
|
28
|
+
renderListItem?: RenderListItemFunction
|
|
29
|
+
renderStyle?: RenderStyleFunction
|
|
30
|
+
spellCheck?: boolean
|
|
31
|
+
}) {
|
|
32
|
+
const editorActor = useContext(EditorActorContext)
|
|
33
|
+
const schema = useSelector(editorActor, (s) => s.context.schema)
|
|
34
|
+
const isInline =
|
|
35
|
+
'__inline' in props.element && props.element.__inline === true
|
|
36
|
+
|
|
37
|
+
if (isInline) {
|
|
38
|
+
const inlineObject = parseInlineObject({
|
|
39
|
+
context: {
|
|
40
|
+
keyGenerator: () => '',
|
|
41
|
+
schema,
|
|
42
|
+
},
|
|
43
|
+
options: {refreshKeys: false},
|
|
44
|
+
inlineObject: {
|
|
45
|
+
_key: props.element._key,
|
|
46
|
+
_type: props.element._type,
|
|
47
|
+
...('value' in props.element && typeof props.element.value === 'object'
|
|
48
|
+
? props.element.value
|
|
49
|
+
: {}),
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (!inlineObject) {
|
|
54
|
+
console.error(
|
|
55
|
+
`Unable to find Inline Object "${props.element._type}" in Schema`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<RenderInlineObject
|
|
61
|
+
attributes={props.attributes}
|
|
62
|
+
element={props.element}
|
|
63
|
+
inlineObject={
|
|
64
|
+
inlineObject ?? {
|
|
65
|
+
_key: props.element._key,
|
|
66
|
+
_type: props.element._type,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
readOnly={props.readOnly}
|
|
70
|
+
renderChild={props.renderChild}
|
|
71
|
+
>
|
|
72
|
+
{props.children}
|
|
73
|
+
</RenderInlineObject>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const textBlock = parseTextBlock({
|
|
78
|
+
context: {
|
|
79
|
+
keyGenerator: () => '',
|
|
80
|
+
schema,
|
|
81
|
+
},
|
|
82
|
+
options: {refreshKeys: false},
|
|
83
|
+
block: props.element,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
if (textBlock) {
|
|
87
|
+
return (
|
|
88
|
+
<RenderTextBlock
|
|
89
|
+
attributes={props.attributes}
|
|
90
|
+
element={props.element}
|
|
91
|
+
readOnly={props.readOnly}
|
|
92
|
+
renderBlock={props.renderBlock}
|
|
93
|
+
renderListItem={props.renderListItem}
|
|
94
|
+
renderStyle={props.renderStyle}
|
|
95
|
+
spellCheck={props.spellCheck}
|
|
96
|
+
textBlock={textBlock}
|
|
97
|
+
>
|
|
98
|
+
{props.children}
|
|
99
|
+
</RenderTextBlock>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const blockObject = parseBlockObject({
|
|
104
|
+
context: {
|
|
105
|
+
keyGenerator: () => '',
|
|
106
|
+
schema,
|
|
107
|
+
},
|
|
108
|
+
options: {refreshKeys: false},
|
|
109
|
+
blockObject: {
|
|
110
|
+
_key: props.element._key,
|
|
111
|
+
_type: props.element._type,
|
|
112
|
+
...('value' in props.element && typeof props.element.value === 'object'
|
|
113
|
+
? props.element.value
|
|
114
|
+
: {}),
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
if (!blockObject) {
|
|
119
|
+
console.error(
|
|
120
|
+
`Unable to find Block Object "${props.element._type}" in Schema`,
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<RenderBlockObject
|
|
126
|
+
attributes={props.attributes}
|
|
127
|
+
blockObject={
|
|
128
|
+
blockObject ?? {
|
|
129
|
+
_key: props.element._key,
|
|
130
|
+
_type: props.element._type,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
element={props.element}
|
|
134
|
+
readOnly={props.readOnly}
|
|
135
|
+
renderBlock={props.renderBlock}
|
|
136
|
+
>
|
|
137
|
+
{props.children}
|
|
138
|
+
</RenderBlockObject>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type {PortableTextObject} from '@sanity/types'
|
|
2
|
+
import {useSelector} from '@xstate/react'
|
|
3
|
+
import {useContext, useRef, type ReactElement} from 'react'
|
|
4
|
+
import {Range, type Element as SlateElement} from 'slate'
|
|
5
|
+
import {DOMEditor} from 'slate-dom'
|
|
6
|
+
import {useSelected, useSlateStatic, type RenderElementProps} from 'slate-react'
|
|
7
|
+
import {getPointBlock} from '../../internal-utils/slate-utils'
|
|
8
|
+
import type {RenderChildFunction} from '../../types/editor'
|
|
9
|
+
import {EditorActorContext} from '../editor-actor-context'
|
|
10
|
+
import {RenderDefaultInlineObject} from './render-default-object'
|
|
11
|
+
|
|
12
|
+
export function RenderInlineObject(props: {
|
|
13
|
+
attributes: RenderElementProps['attributes']
|
|
14
|
+
children: ReactElement
|
|
15
|
+
element: SlateElement
|
|
16
|
+
inlineObject: PortableTextObject
|
|
17
|
+
readOnly: boolean
|
|
18
|
+
renderChild?: RenderChildFunction
|
|
19
|
+
}) {
|
|
20
|
+
const inlineObjectRef = useRef<HTMLElement>(null)
|
|
21
|
+
|
|
22
|
+
const slateEditor = useSlateStatic()
|
|
23
|
+
const selected = useSelected()
|
|
24
|
+
|
|
25
|
+
const editorActor = useContext(EditorActorContext)
|
|
26
|
+
const legacySchemaType = useSelector(editorActor, (s) =>
|
|
27
|
+
s.context
|
|
28
|
+
.getLegacySchema()
|
|
29
|
+
.inlineObjects.find(
|
|
30
|
+
(inlineObject) => inlineObject.name === props.element._type,
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if (!legacySchemaType) {
|
|
35
|
+
console.error(
|
|
36
|
+
`Inline object type ${props.element._type} not found in Schema`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const focused =
|
|
41
|
+
selected &&
|
|
42
|
+
slateEditor.selection !== null &&
|
|
43
|
+
Range.isCollapsed(slateEditor.selection)
|
|
44
|
+
const path = DOMEditor.findPath(slateEditor, props.element)
|
|
45
|
+
const [block] = getPointBlock({
|
|
46
|
+
editor: slateEditor,
|
|
47
|
+
point: {
|
|
48
|
+
path,
|
|
49
|
+
offset: 0,
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (!block) {
|
|
54
|
+
console.error(
|
|
55
|
+
`Unable to find parent block of inline object ${props.element._key}`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<span
|
|
61
|
+
{...props.attributes}
|
|
62
|
+
draggable={!props.readOnly}
|
|
63
|
+
className="pt-inline-object"
|
|
64
|
+
data-child-key={props.inlineObject._key}
|
|
65
|
+
data-child-name={props.inlineObject._type}
|
|
66
|
+
data-child-type="object"
|
|
67
|
+
>
|
|
68
|
+
{props.children}
|
|
69
|
+
<span ref={inlineObjectRef} style={{display: 'inline-block'}}>
|
|
70
|
+
{props.renderChild && block && legacySchemaType ? (
|
|
71
|
+
props.renderChild({
|
|
72
|
+
annotations: [],
|
|
73
|
+
children: (
|
|
74
|
+
<RenderDefaultInlineObject inlineObject={props.inlineObject} />
|
|
75
|
+
),
|
|
76
|
+
editorElementRef: inlineObjectRef,
|
|
77
|
+
selected,
|
|
78
|
+
focused,
|
|
79
|
+
path: [{_key: block._key}, 'children', {_key: props.element._key}],
|
|
80
|
+
schemaType: legacySchemaType,
|
|
81
|
+
value: props.inlineObject,
|
|
82
|
+
type: legacySchemaType,
|
|
83
|
+
})
|
|
84
|
+
) : (
|
|
85
|
+
<RenderDefaultInlineObject inlineObject={props.inlineObject} />
|
|
86
|
+
)}
|
|
87
|
+
</span>
|
|
88
|
+
</span>
|
|
89
|
+
)
|
|
90
|
+
}
|