@portabletext/editor 1.44.11 → 1.44.13
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/behavior.core.cjs +38 -8
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/editor-provider.cjs +51 -29
- package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +38 -8
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/editor-provider.js +51 -29
- package/lib/_chunks-es/editor-provider.js.map +1 -1
- package/lib/index.cjs +20 -16
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +20 -16
- package/lib/index.js.map +1 -1
- package/package.json +7 -7
- package/src/behaviors/behavior.core.block-objects.ts +56 -8
- package/src/editor/Editable.tsx +24 -21
- package/src/editor/define-schema.ts +45 -9
- package/src/editor/editor-machine.ts +1 -0
- package/src/internal-utils/event-position.ts +9 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.44.
|
|
3
|
+
"version": "1.44.13",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -89,14 +89,14 @@
|
|
|
89
89
|
"@sanity/schema": "^3.82.0",
|
|
90
90
|
"@sanity/types": "^3.82.0",
|
|
91
91
|
"@testing-library/jest-dom": "^6.6.3",
|
|
92
|
-
"@testing-library/react": "^16.
|
|
92
|
+
"@testing-library/react": "^16.3.0",
|
|
93
93
|
"@types/debug": "^4.1.12",
|
|
94
94
|
"@types/lodash": "^4.17.13",
|
|
95
95
|
"@types/lodash.startcase": "^4.4.9",
|
|
96
|
-
"@types/react": "^19.0
|
|
97
|
-
"@types/react-dom": "^19.
|
|
98
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
99
|
-
"@typescript-eslint/parser": "^8.
|
|
96
|
+
"@types/react": "^19.1.0",
|
|
97
|
+
"@types/react-dom": "^19.1.1",
|
|
98
|
+
"@typescript-eslint/eslint-plugin": "^8.29.0",
|
|
99
|
+
"@typescript-eslint/parser": "^8.29.0",
|
|
100
100
|
"@vitejs/plugin-react": "^4.3.4",
|
|
101
101
|
"@vitest/browser": "^3.1.1",
|
|
102
102
|
"@vitest/coverage-istanbul": "^3.1.1",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"react-dom": "^19.1.0",
|
|
110
110
|
"rxjs": "^7.8.2",
|
|
111
111
|
"typescript": "5.8.2",
|
|
112
|
-
"vite": "^6.2.
|
|
112
|
+
"vite": "^6.2.5",
|
|
113
113
|
"vitest": "^3.1.1",
|
|
114
114
|
"vitest-browser-react": "^0.1.1",
|
|
115
115
|
"racejar": "1.2.3"
|
|
@@ -95,12 +95,31 @@ const breakingBlockObject = defineBehavior({
|
|
|
95
95
|
const clickingAboveLonelyBlockObject = defineBehavior({
|
|
96
96
|
on: 'mouse.click',
|
|
97
97
|
guard: ({snapshot, event}) => {
|
|
98
|
-
if (
|
|
98
|
+
if (snapshot.context.readOnly) {
|
|
99
99
|
return false
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (
|
|
103
|
+
snapshot.context.selection &&
|
|
104
|
+
!selectors.isSelectionCollapsed(snapshot)
|
|
105
|
+
) {
|
|
106
|
+
return false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const focusBlockObject = selectors.getFocusBlockObject({
|
|
110
|
+
...snapshot,
|
|
111
|
+
context: {
|
|
112
|
+
...snapshot.context,
|
|
113
|
+
selection: event.position.selection,
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
const previousBlock = selectors.getPreviousBlock({
|
|
117
|
+
...snapshot,
|
|
118
|
+
context: {
|
|
119
|
+
...snapshot.context,
|
|
120
|
+
selection: event.position.selection,
|
|
121
|
+
},
|
|
122
|
+
})
|
|
104
123
|
|
|
105
124
|
return (
|
|
106
125
|
event.position.isEditor &&
|
|
@@ -110,13 +129,18 @@ const clickingAboveLonelyBlockObject = defineBehavior({
|
|
|
110
129
|
)
|
|
111
130
|
},
|
|
112
131
|
actions: [
|
|
113
|
-
({snapshot}) => [
|
|
132
|
+
({snapshot, event}) => [
|
|
133
|
+
raise({
|
|
134
|
+
type: 'select',
|
|
135
|
+
selection: event.position.selection,
|
|
136
|
+
}),
|
|
114
137
|
raise({
|
|
115
138
|
type: 'insert.block',
|
|
116
139
|
block: {
|
|
117
140
|
_type: snapshot.context.schema.block.name,
|
|
118
141
|
},
|
|
119
142
|
placement: 'before',
|
|
143
|
+
select: 'start',
|
|
120
144
|
}),
|
|
121
145
|
],
|
|
122
146
|
],
|
|
@@ -125,12 +149,31 @@ const clickingAboveLonelyBlockObject = defineBehavior({
|
|
|
125
149
|
const clickingBelowLonelyBlockObject = defineBehavior({
|
|
126
150
|
on: 'mouse.click',
|
|
127
151
|
guard: ({snapshot, event}) => {
|
|
128
|
-
if (
|
|
152
|
+
if (snapshot.context.readOnly) {
|
|
129
153
|
return false
|
|
130
154
|
}
|
|
131
155
|
|
|
132
|
-
|
|
133
|
-
|
|
156
|
+
if (
|
|
157
|
+
snapshot.context.selection &&
|
|
158
|
+
!selectors.isSelectionCollapsed(snapshot)
|
|
159
|
+
) {
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const focusBlockObject = selectors.getFocusBlockObject({
|
|
164
|
+
...snapshot,
|
|
165
|
+
context: {
|
|
166
|
+
...snapshot.context,
|
|
167
|
+
selection: event.position.selection,
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
const nextBlock = selectors.getNextBlock({
|
|
171
|
+
...snapshot,
|
|
172
|
+
context: {
|
|
173
|
+
...snapshot.context,
|
|
174
|
+
selection: event.position.selection,
|
|
175
|
+
},
|
|
176
|
+
})
|
|
134
177
|
|
|
135
178
|
return (
|
|
136
179
|
event.position.isEditor &&
|
|
@@ -140,13 +183,18 @@ const clickingBelowLonelyBlockObject = defineBehavior({
|
|
|
140
183
|
)
|
|
141
184
|
},
|
|
142
185
|
actions: [
|
|
143
|
-
({snapshot}) => [
|
|
186
|
+
({snapshot, event}) => [
|
|
187
|
+
raise({
|
|
188
|
+
type: 'select',
|
|
189
|
+
selection: event.position.selection,
|
|
190
|
+
}),
|
|
144
191
|
raise({
|
|
145
192
|
type: 'insert.block',
|
|
146
193
|
block: {
|
|
147
194
|
_type: snapshot.context.schema.block.name,
|
|
148
195
|
},
|
|
149
196
|
placement: 'after',
|
|
197
|
+
select: 'start',
|
|
150
198
|
}),
|
|
151
199
|
],
|
|
152
200
|
],
|
package/src/editor/Editable.tsx
CHANGED
|
@@ -372,7 +372,13 @@ export const PortableTextEditable = forwardRef<
|
|
|
372
372
|
event.stopPropagation()
|
|
373
373
|
event.preventDefault()
|
|
374
374
|
|
|
375
|
-
const selection =
|
|
375
|
+
const selection = slateEditor.selection
|
|
376
|
+
? slateRangeToSelection({
|
|
377
|
+
schema: editorActor.getSnapshot().context.schema,
|
|
378
|
+
editor: slateEditor,
|
|
379
|
+
range: slateEditor.selection,
|
|
380
|
+
})
|
|
381
|
+
: undefined
|
|
376
382
|
const position = selection ? {selection} : undefined
|
|
377
383
|
|
|
378
384
|
if (!position) {
|
|
@@ -586,25 +592,22 @@ export const PortableTextEditable = forwardRef<
|
|
|
586
592
|
}
|
|
587
593
|
|
|
588
594
|
const position = getEventPosition({
|
|
589
|
-
|
|
595
|
+
editorActor,
|
|
590
596
|
slateEditor,
|
|
591
597
|
event: event.nativeEvent,
|
|
592
598
|
})
|
|
593
599
|
|
|
594
|
-
if (
|
|
595
|
-
|
|
596
|
-
|
|
600
|
+
if (position) {
|
|
601
|
+
editorActor.send({
|
|
602
|
+
type: 'behavior event',
|
|
603
|
+
behaviorEvent: {
|
|
604
|
+
type: 'mouse.click',
|
|
605
|
+
position,
|
|
606
|
+
},
|
|
607
|
+
editor: slateEditor,
|
|
608
|
+
nativeEvent: event,
|
|
609
|
+
})
|
|
597
610
|
}
|
|
598
|
-
|
|
599
|
-
editorActor.send({
|
|
600
|
-
type: 'behavior event',
|
|
601
|
-
behaviorEvent: {
|
|
602
|
-
type: 'mouse.click',
|
|
603
|
-
position,
|
|
604
|
-
},
|
|
605
|
-
editor: slateEditor,
|
|
606
|
-
nativeEvent: event,
|
|
607
|
-
})
|
|
608
611
|
},
|
|
609
612
|
[onClick, editorActor, slateEditor],
|
|
610
613
|
)
|
|
@@ -819,7 +822,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
819
822
|
}
|
|
820
823
|
|
|
821
824
|
const position = getEventPosition({
|
|
822
|
-
|
|
825
|
+
editorActor,
|
|
823
826
|
slateEditor,
|
|
824
827
|
event: event.nativeEvent,
|
|
825
828
|
})
|
|
@@ -985,7 +988,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
985
988
|
}
|
|
986
989
|
|
|
987
990
|
const position = getEventPosition({
|
|
988
|
-
|
|
991
|
+
editorActor,
|
|
989
992
|
slateEditor,
|
|
990
993
|
event: event.nativeEvent,
|
|
991
994
|
})
|
|
@@ -1045,7 +1048,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1045
1048
|
}
|
|
1046
1049
|
|
|
1047
1050
|
const position = getEventPosition({
|
|
1048
|
-
|
|
1051
|
+
editorActor,
|
|
1049
1052
|
slateEditor,
|
|
1050
1053
|
event: event.nativeEvent,
|
|
1051
1054
|
})
|
|
@@ -1081,7 +1084,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1081
1084
|
}
|
|
1082
1085
|
|
|
1083
1086
|
const position = getEventPosition({
|
|
1084
|
-
|
|
1087
|
+
editorActor,
|
|
1085
1088
|
slateEditor,
|
|
1086
1089
|
event: event.nativeEvent,
|
|
1087
1090
|
})
|
|
@@ -1118,7 +1121,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1118
1121
|
}
|
|
1119
1122
|
|
|
1120
1123
|
const position = getEventPosition({
|
|
1121
|
-
|
|
1124
|
+
editorActor,
|
|
1122
1125
|
slateEditor,
|
|
1123
1126
|
event: event.nativeEvent,
|
|
1124
1127
|
})
|
|
@@ -1156,7 +1159,7 @@ export const PortableTextEditable = forwardRef<
|
|
|
1156
1159
|
}
|
|
1157
1160
|
|
|
1158
1161
|
const position = getEventPosition({
|
|
1159
|
-
|
|
1162
|
+
editorActor,
|
|
1160
1163
|
slateEditor,
|
|
1161
1164
|
event: event.nativeEvent,
|
|
1162
1165
|
})
|
|
@@ -3,6 +3,7 @@ import {defineField, defineType, type ObjectSchemaType} from '@sanity/types'
|
|
|
3
3
|
import startCase from 'lodash.startcase'
|
|
4
4
|
import type {PortableTextMemberSchemaTypes} from '../types/editor'
|
|
5
5
|
import {createEditorSchema} from './create-editor-schema'
|
|
6
|
+
import {defaultKeyGenerator} from './key-generator'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @public
|
|
@@ -55,6 +56,24 @@ export function defineSchema<const TSchemaDefinition extends SchemaDefinition>(
|
|
|
55
56
|
return definition
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
const temporaryImageName = `tmp-${defaultKeyGenerator()}-image`
|
|
60
|
+
const temporaryUrlName = `tmp-${defaultKeyGenerator()}-url`
|
|
61
|
+
|
|
62
|
+
const temporaryObjectNames: Record<string, string> = {
|
|
63
|
+
image: temporaryImageName,
|
|
64
|
+
url: temporaryUrlName,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const objectNames: Record<string, string> = {
|
|
68
|
+
[temporaryImageName]: 'image',
|
|
69
|
+
[temporaryUrlName]: 'url',
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const defaultObjectTitles: Record<string, string> = {
|
|
73
|
+
image: 'Image',
|
|
74
|
+
url: 'URL',
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
/**
|
|
59
78
|
* @public
|
|
60
79
|
*/
|
|
@@ -68,21 +87,30 @@ export function compileSchemaDefinition<
|
|
|
68
87
|
defineType({
|
|
69
88
|
type: 'object',
|
|
70
89
|
// Very naive way to work around `SanitySchema.compile` adding default
|
|
71
|
-
// fields to objects with
|
|
72
|
-
name: blockObject.name
|
|
90
|
+
// fields to objects with certain names.
|
|
91
|
+
name: temporaryObjectNames[blockObject.name] ?? blockObject.name,
|
|
73
92
|
title:
|
|
74
|
-
blockObject.
|
|
75
|
-
?
|
|
93
|
+
blockObject.title === undefined
|
|
94
|
+
? // This avoids the default title which is a title case of the object name
|
|
95
|
+
defaultObjectTitles[blockObject.name]
|
|
76
96
|
: blockObject.title,
|
|
77
97
|
fields: [],
|
|
78
98
|
}),
|
|
79
99
|
) ?? []
|
|
100
|
+
|
|
80
101
|
const inlineObjects =
|
|
81
102
|
definition?.inlineObjects?.map((inlineObject) =>
|
|
82
103
|
defineType({
|
|
83
104
|
type: 'object',
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
// Very naive way to work around `SanitySchema.compile` adding default
|
|
106
|
+
// fields to objects with certain names.
|
|
107
|
+
name: temporaryObjectNames[inlineObject.name] ?? inlineObject.name,
|
|
108
|
+
|
|
109
|
+
title:
|
|
110
|
+
inlineObject.title === undefined
|
|
111
|
+
? // This avoids the default title which is a title case of the object name
|
|
112
|
+
defaultObjectTitles[inlineObject.name]
|
|
113
|
+
: inlineObject.title,
|
|
86
114
|
fields: [],
|
|
87
115
|
}),
|
|
88
116
|
) ?? []
|
|
@@ -132,16 +160,24 @@ export function compileSchemaDefinition<
|
|
|
132
160
|
return {
|
|
133
161
|
...pteSchema,
|
|
134
162
|
blockObjects: pteSchema.blockObjects.map((blockObject) =>
|
|
135
|
-
blockObject.name
|
|
163
|
+
objectNames[blockObject.name] !== undefined
|
|
136
164
|
? ({
|
|
137
165
|
...blockObject,
|
|
138
|
-
name:
|
|
166
|
+
name: objectNames[blockObject.name],
|
|
139
167
|
type: {
|
|
140
168
|
...blockObject.type,
|
|
141
|
-
name:
|
|
169
|
+
name: objectNames[blockObject.name],
|
|
142
170
|
},
|
|
143
171
|
} as ObjectSchemaType)
|
|
144
172
|
: blockObject,
|
|
145
173
|
),
|
|
174
|
+
inlineObjects: pteSchema.inlineObjects.map((inlineObject) =>
|
|
175
|
+
objectNames[inlineObject.name] !== undefined
|
|
176
|
+
? ({
|
|
177
|
+
...inlineObject,
|
|
178
|
+
name: objectNames[inlineObject.name],
|
|
179
|
+
} as ObjectSchemaType)
|
|
180
|
+
: inlineObject,
|
|
181
|
+
),
|
|
146
182
|
} satisfies EditorSchema
|
|
147
183
|
}
|
|
@@ -382,6 +382,7 @@ export const editorMachine = setup({
|
|
|
382
382
|
actions: 'handle behavior event',
|
|
383
383
|
guard: ({event}) =>
|
|
384
384
|
event.behaviorEvent.type === 'clipboard.copy' ||
|
|
385
|
+
event.behaviorEvent.type === 'mouse.click' ||
|
|
385
386
|
event.behaviorEvent.type === 'serialize' ||
|
|
386
387
|
event.behaviorEvent.type === 'serialization.failure' ||
|
|
387
388
|
event.behaviorEvent.type === 'serialization.success' ||
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {Editor, type BaseRange, type Node} from 'slate'
|
|
2
2
|
import {DOMEditor, isDOMNode} from 'slate-dom'
|
|
3
3
|
import type {EditorSchema, EditorSelection} from '..'
|
|
4
|
+
import type {EditorActor} from '../editor/editor-machine'
|
|
4
5
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
5
6
|
import * as utils from '../utils'
|
|
6
7
|
import {
|
|
@@ -21,14 +22,18 @@ export type EventPosition = {
|
|
|
21
22
|
export type EventPositionBlock = EventPosition['block']
|
|
22
23
|
|
|
23
24
|
export function getEventPosition({
|
|
24
|
-
|
|
25
|
+
editorActor,
|
|
25
26
|
slateEditor,
|
|
26
27
|
event,
|
|
27
28
|
}: {
|
|
28
|
-
|
|
29
|
+
editorActor: EditorActor
|
|
29
30
|
slateEditor: PortableTextSlateEditor
|
|
30
31
|
event: DragEvent | MouseEvent
|
|
31
32
|
}): EventPosition | undefined {
|
|
33
|
+
if (editorActor.getSnapshot().matches({setup: 'setting up'})) {
|
|
34
|
+
return undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
32
37
|
const node = getEventNode({slateEditor, event})
|
|
33
38
|
|
|
34
39
|
if (!node) {
|
|
@@ -37,13 +42,13 @@ export function getEventPosition({
|
|
|
37
42
|
|
|
38
43
|
const block = getNodeBlock({
|
|
39
44
|
editor: slateEditor,
|
|
40
|
-
schema,
|
|
45
|
+
schema: editorActor.getSnapshot().context.schema,
|
|
41
46
|
node,
|
|
42
47
|
})
|
|
43
48
|
|
|
44
49
|
const positionBlock = getEventPositionBlock({node, slateEditor, event})
|
|
45
50
|
const selection = getEventSelection({
|
|
46
|
-
schema,
|
|
51
|
+
schema: editorActor.getSnapshot().context.schema,
|
|
47
52
|
slateEditor,
|
|
48
53
|
event,
|
|
49
54
|
})
|