@portabletext/editor 1.47.3 → 1.47.4
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 +125 -100
- package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
- package/lib/_chunks-cjs/util.is-selection-collapsed.cjs +0 -5
- package/lib/_chunks-cjs/util.is-selection-collapsed.cjs.map +1 -1
- package/lib/_chunks-es/editor-provider.js +126 -101
- package/lib/_chunks-es/editor-provider.js.map +1 -1
- package/lib/_chunks-es/util.is-selection-collapsed.js +0 -5
- package/lib/_chunks-es/util.is-selection-collapsed.js.map +1 -1
- package/lib/behaviors/index.d.cts +404 -543
- package/lib/behaviors/index.d.ts +404 -543
- package/lib/index.cjs +3 -8
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +411 -34
- package/lib/index.d.ts +411 -34
- package/lib/index.js +4 -9
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.cts +411 -34
- package/lib/plugins/index.d.ts +411 -34
- package/lib/selectors/index.d.cts +404 -33
- package/lib/selectors/index.d.ts +404 -33
- package/lib/utils/index.cjs +4 -1
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.cts +404 -33
- package/lib/utils/index.d.ts +404 -33
- package/lib/utils/index.js +6 -3
- package/lib/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/behavior-actions/behavior.action.insert.text.ts +10 -1
- package/src/behavior-actions/behavior.actions.ts +0 -18
- package/src/behaviors/behavior.perform-event.ts +55 -65
- package/src/behaviors/behavior.types.event.ts +7 -9
- package/src/editor/Editable.tsx +4 -17
- package/src/editor/create-editor.ts +14 -0
- package/src/editor/editor-machine.ts +76 -5
- package/src/editor/plugins/create-with-event-listeners.ts +0 -6
- package/src/editor/plugins/createWithEditableAPI.ts +2 -8
- package/src/editor/with-applying-behavior-actions.ts +2 -2
- package/src/behavior-actions/behavior.action.blur.ts +0 -8
- package/src/behavior-actions/behavior.action.focus.ts +0 -8
package/lib/utils/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { sliceBlocks, isSpan } from "../_chunks-es/util.slice-blocks.js";
|
|
2
|
-
import { blockOffsetToSpanSelectionPoint, getBlockEndPoint, getBlockStartPoint, getTextBlockText, isEmptyTextBlock,
|
|
1
|
+
import { isEqualSelectionPoints, sliceBlocks, isSpan } from "../_chunks-es/util.slice-blocks.js";
|
|
2
|
+
import { blockOffsetToSpanSelectionPoint, getBlockEndPoint, getBlockStartPoint, getTextBlockText, isEmptyTextBlock, isKeyedSegment, reverseSelection, spanSelectionPointToBlockOffset } from "../_chunks-es/util.slice-blocks.js";
|
|
3
3
|
import { blockOffsetToBlockSelectionPoint, blockOffsetToSelectionPoint, blockOffsetsToSelection, childSelectionPointToBlockOffset, selectionPointToBlockOffset } from "../_chunks-es/util.selection-point-to-block-offset.js";
|
|
4
|
-
import { getSelectionEndPoint,
|
|
4
|
+
import { getSelectionEndPoint, isSelectionCollapsed } from "../_chunks-es/util.is-selection-collapsed.js";
|
|
5
5
|
import { isTextBlock } from "../_chunks-es/util.merge-text-blocks.js";
|
|
6
6
|
import { mergeTextBlocks } from "../_chunks-es/util.merge-text-blocks.js";
|
|
7
7
|
function getSelectionStartPoint(selection) {
|
|
8
8
|
return selection ? selection.backward ? selection.focus : selection.anchor : null;
|
|
9
9
|
}
|
|
10
|
+
function isEqualSelections(a, b) {
|
|
11
|
+
return !a && !b ? !0 : !a || !b ? !1 : isEqualSelectionPoints(a.anchor, b.anchor) && isEqualSelectionPoints(a.focus, b.focus);
|
|
12
|
+
}
|
|
10
13
|
function splitTextBlock({
|
|
11
14
|
context,
|
|
12
15
|
block,
|
package/lib/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/utils/util.get-selection-start-point.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["import type {EditorSelection, EditorSelectionPoint} from '..'\n\n/**\n * @public\n */\nexport function getSelectionStartPoint<\n TEditorSelection extends NonNullable<EditorSelection> | null,\n TEditorSelectionPoint extends\n EditorSelectionPoint | null = TEditorSelection extends NonNullable<EditorSelection>\n ? EditorSelectionPoint\n : null,\n>(selection: TEditorSelection): TEditorSelectionPoint {\n if (!selection) {\n return null as TEditorSelectionPoint\n }\n\n return (\n selection.backward ? selection.focus : selection.anchor\n ) as TEditorSelectionPoint\n}\n","import type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorSelectionPoint} from '..'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {isSpan} from './util.is-span'\nimport {isTextBlock} from './util.is-text-block'\nimport {sliceBlocks} from './util.slice-blocks'\n\n/**\n * @beta\n */\nexport function splitTextBlock({\n context,\n block,\n point,\n}: {\n context: Pick<EditorContext, 'schema'>\n block: PortableTextTextBlock\n point: EditorSelectionPoint\n}): {before: PortableTextTextBlock; after: PortableTextTextBlock} | undefined {\n const firstChild = block.children.at(0)\n const lastChild = block.children.at(block.children.length - 1)\n\n if (!firstChild || !lastChild) {\n return undefined\n }\n\n const before = sliceBlocks({\n blocks: [block],\n selection: {\n anchor: {\n path: [{_key: block._key}, 'children', {_key: firstChild._key}],\n offset: 0,\n },\n focus: point,\n },\n }).at(0)\n const after = sliceBlocks({\n blocks: [block],\n selection: {\n anchor: point,\n focus: {\n path: [{_key: block._key}, 'children', {_key: lastChild._key}],\n offset: isSpan(context, lastChild) ? lastChild.text.length : 0,\n },\n },\n }).at(0)\n\n if (!before || !after) {\n return undefined\n }\n\n if (!isTextBlock(context, before) || !isTextBlock(context, after)) {\n return undefined\n }\n\n return {before, after}\n}\n"],"names":["getSelectionStartPoint","selection","backward","focus","anchor","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceBlocks","blocks","path","_key","offset","after","isSpan","text","isTextBlock"],"mappings":";;;;;;AAKO,SAASA,uBAMdC,WAAoD;AACpD,SAAKA,YAKHA,UAAUC,WAAWD,UAAUE,QAAQF,UAAUG,SAJ1C;AAMX;ACTO,
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/utils/util.get-selection-start-point.ts","../../src/utils/util.is-equal-selections.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["import type {EditorSelection, EditorSelectionPoint} from '..'\n\n/**\n * @public\n */\nexport function getSelectionStartPoint<\n TEditorSelection extends NonNullable<EditorSelection> | null,\n TEditorSelectionPoint extends\n EditorSelectionPoint | null = TEditorSelection extends NonNullable<EditorSelection>\n ? EditorSelectionPoint\n : null,\n>(selection: TEditorSelection): TEditorSelectionPoint {\n if (!selection) {\n return null as TEditorSelectionPoint\n }\n\n return (\n selection.backward ? selection.focus : selection.anchor\n ) as TEditorSelectionPoint\n}\n","import type {EditorSelection} from '../types/editor'\nimport {isEqualSelectionPoints} from './util.is-equal-selection-points'\n\n/**\n * @public\n */\nexport function isEqualSelections(a: EditorSelection, b: EditorSelection) {\n if (!a && !b) {\n return true\n }\n\n if (!a || !b) {\n return false\n }\n\n return (\n isEqualSelectionPoints(a.anchor, b.anchor) &&\n isEqualSelectionPoints(a.focus, b.focus)\n )\n}\n","import type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorSelectionPoint} from '..'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {isSpan} from './util.is-span'\nimport {isTextBlock} from './util.is-text-block'\nimport {sliceBlocks} from './util.slice-blocks'\n\n/**\n * @beta\n */\nexport function splitTextBlock({\n context,\n block,\n point,\n}: {\n context: Pick<EditorContext, 'schema'>\n block: PortableTextTextBlock\n point: EditorSelectionPoint\n}): {before: PortableTextTextBlock; after: PortableTextTextBlock} | undefined {\n const firstChild = block.children.at(0)\n const lastChild = block.children.at(block.children.length - 1)\n\n if (!firstChild || !lastChild) {\n return undefined\n }\n\n const before = sliceBlocks({\n blocks: [block],\n selection: {\n anchor: {\n path: [{_key: block._key}, 'children', {_key: firstChild._key}],\n offset: 0,\n },\n focus: point,\n },\n }).at(0)\n const after = sliceBlocks({\n blocks: [block],\n selection: {\n anchor: point,\n focus: {\n path: [{_key: block._key}, 'children', {_key: lastChild._key}],\n offset: isSpan(context, lastChild) ? lastChild.text.length : 0,\n },\n },\n }).at(0)\n\n if (!before || !after) {\n return undefined\n }\n\n if (!isTextBlock(context, before) || !isTextBlock(context, after)) {\n return undefined\n }\n\n return {before, after}\n}\n"],"names":["getSelectionStartPoint","selection","backward","focus","anchor","isEqualSelections","a","b","isEqualSelectionPoints","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceBlocks","blocks","path","_key","offset","after","isSpan","text","isTextBlock"],"mappings":";;;;;;AAKO,SAASA,uBAMdC,WAAoD;AACpD,SAAKA,YAKHA,UAAUC,WAAWD,UAAUE,QAAQF,UAAUG,SAJ1C;AAMX;ACbgBC,SAAAA,kBAAkBC,GAAoBC,GAAoB;AACpE,SAAA,CAACD,KAAK,CAACC,IACF,KAGL,CAACD,KAAK,CAACC,IACF,KAIPC,uBAAuBF,EAAEF,QAAQG,EAAEH,MAAM,KACzCI,uBAAuBF,EAAEH,OAAOI,EAAEJ,KAAK;AAE3C;ACTO,SAASM,eAAe;AAAA,EAC7BC;AAAAA,EACAC;AAAAA,EACAC;AAKF,GAA8E;AAC5E,QAAMC,aAAaF,MAAMG,SAASC,GAAG,CAAC,GAChCC,YAAYL,MAAMG,SAASC,GAAGJ,MAAMG,SAASG,SAAS,CAAC;AAEzD,MAAA,CAACJ,cAAc,CAACG;AAClB;AAGF,QAAME,SAASC,YAAY;AAAA,IACzBC,QAAQ,CAACT,KAAK;AAAA,IACdV,WAAW;AAAA,MACTG,QAAQ;AAAA,QACNiB,MAAM,CAAC;AAAA,UAACC,MAAMX,MAAMW;AAAAA,WAAO,YAAY;AAAA,UAACA,MAAMT,WAAWS;AAAAA,QAAAA,CAAK;AAAA,QAC9DC,QAAQ;AAAA,MACV;AAAA,MACApB,OAAOS;AAAAA,IAAAA;AAAAA,EAEV,CAAA,EAAEG,GAAG,CAAC,GACDS,QAAQL,YAAY;AAAA,IACxBC,QAAQ,CAACT,KAAK;AAAA,IACdV,WAAW;AAAA,MACTG,QAAQQ;AAAAA,MACRT,OAAO;AAAA,QACLkB,MAAM,CAAC;AAAA,UAACC,MAAMX,MAAMW;AAAAA,WAAO,YAAY;AAAA,UAACA,MAAMN,UAAUM;AAAAA,QAAAA,CAAK;AAAA,QAC7DC,QAAQE,OAAOf,SAASM,SAAS,IAAIA,UAAUU,KAAKT,SAAS;AAAA,MAAA;AAAA,IAC/D;AAAA,EACF,CACD,EAAEF,GAAG,CAAC;AAEP,MAAI,EAACG,CAAAA,UAAU,CAACM,UAIZ,EAACG,CAAAA,YAAYjB,SAASQ,MAAM,KAAK,CAACS,YAAYjB,SAASc,KAAK;AAIzD,WAAA;AAAA,MAACN;AAAAA,MAAQM;AAAAA,IAAK;AACvB;"}
|
package/package.json
CHANGED
|
@@ -4,5 +4,14 @@ import type {BehaviorActionImplementation} from './behavior.actions'
|
|
|
4
4
|
export const insertTextActionImplementation: BehaviorActionImplementation<
|
|
5
5
|
'insert.text'
|
|
6
6
|
> = ({action}) => {
|
|
7
|
-
|
|
7
|
+
if (action.editor.marks) {
|
|
8
|
+
Transforms.insertNodes(action.editor, {
|
|
9
|
+
text: action.text,
|
|
10
|
+
...action.editor.marks,
|
|
11
|
+
})
|
|
12
|
+
} else {
|
|
13
|
+
Transforms.insertText(action.editor, action.text)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
action.editor.marks = null
|
|
8
17
|
}
|
|
@@ -12,14 +12,12 @@ import {addAnnotationActionImplementation} from './behavior.action.annotation.ad
|
|
|
12
12
|
import {removeAnnotationActionImplementation} from './behavior.action.annotation.remove'
|
|
13
13
|
import {blockSetBehaviorActionImplementation} from './behavior.action.block.set'
|
|
14
14
|
import {blockUnsetBehaviorActionImplementation} from './behavior.action.block.unset'
|
|
15
|
-
import {blurActionImplementation} from './behavior.action.blur'
|
|
16
15
|
import {decoratorAddActionImplementation} from './behavior.action.decorator.add'
|
|
17
16
|
import {deleteActionImplementation} from './behavior.action.delete'
|
|
18
17
|
import {deleteBackwardActionImplementation} from './behavior.action.delete.backward'
|
|
19
18
|
import {deleteBlockActionImplementation} from './behavior.action.delete.block'
|
|
20
19
|
import {deleteForwardActionImplementation} from './behavior.action.delete.forward'
|
|
21
20
|
import {effectActionImplementation} from './behavior.action.effect'
|
|
22
|
-
import {focusActionImplementation} from './behavior.action.focus'
|
|
23
21
|
import {insertInlineObjectActionImplementation} from './behavior.action.insert-inline-object'
|
|
24
22
|
import {insertSpanActionImplementation} from './behavior.action.insert-span'
|
|
25
23
|
import {insertBlockActionImplementation} from './behavior.action.insert.block'
|
|
@@ -58,10 +56,8 @@ const behaviorActionImplementations: BehaviorActionImplementations = {
|
|
|
58
56
|
'annotation.remove': removeAnnotationActionImplementation,
|
|
59
57
|
'block.set': blockSetBehaviorActionImplementation,
|
|
60
58
|
'block.unset': blockUnsetBehaviorActionImplementation,
|
|
61
|
-
'blur': blurActionImplementation,
|
|
62
59
|
'decorator.add': decoratorAddActionImplementation,
|
|
63
60
|
'decorator.remove': removeDecoratorActionImplementation,
|
|
64
|
-
'focus': focusActionImplementation,
|
|
65
61
|
'delete': deleteActionImplementation,
|
|
66
62
|
'delete.backward': deleteBackwardActionImplementation,
|
|
67
63
|
'delete.forward': deleteForwardActionImplementation,
|
|
@@ -119,13 +115,6 @@ export function performAction({
|
|
|
119
115
|
})
|
|
120
116
|
break
|
|
121
117
|
}
|
|
122
|
-
case 'blur': {
|
|
123
|
-
behaviorActionImplementations.blur({
|
|
124
|
-
context,
|
|
125
|
-
action,
|
|
126
|
-
})
|
|
127
|
-
break
|
|
128
|
-
}
|
|
129
118
|
case 'decorator.add': {
|
|
130
119
|
behaviorActionImplementations['decorator.add']({
|
|
131
120
|
context,
|
|
@@ -175,13 +164,6 @@ export function performAction({
|
|
|
175
164
|
})
|
|
176
165
|
break
|
|
177
166
|
}
|
|
178
|
-
case 'focus': {
|
|
179
|
-
behaviorActionImplementations.focus({
|
|
180
|
-
context,
|
|
181
|
-
action,
|
|
182
|
-
})
|
|
183
|
-
break
|
|
184
|
-
}
|
|
185
167
|
case 'history.redo': {
|
|
186
168
|
behaviorActionImplementations['history.redo']({
|
|
187
169
|
context,
|
|
@@ -37,7 +37,6 @@ export function performEvent({
|
|
|
37
37
|
schema,
|
|
38
38
|
getSnapshot,
|
|
39
39
|
nativeEvent,
|
|
40
|
-
defaultActionCallback,
|
|
41
40
|
}: {
|
|
42
41
|
mode: 'raise' | 'execute'
|
|
43
42
|
behaviors: Array<Behavior>
|
|
@@ -46,7 +45,6 @@ export function performEvent({
|
|
|
46
45
|
keyGenerator: () => string
|
|
47
46
|
schema: EditorSchema
|
|
48
47
|
getSnapshot: () => EditorSnapshot
|
|
49
|
-
defaultActionCallback: (() => void) | undefined
|
|
50
48
|
nativeEvent:
|
|
51
49
|
| {
|
|
52
50
|
preventDefault: () => void
|
|
@@ -105,21 +103,6 @@ export function performEvent({
|
|
|
105
103
|
})
|
|
106
104
|
|
|
107
105
|
if (eventBehaviors.length === 0) {
|
|
108
|
-
if (defaultActionCallback) {
|
|
109
|
-
withApplyingBehaviorActions(editor, () => {
|
|
110
|
-
try {
|
|
111
|
-
defaultActionCallback()
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.error(
|
|
114
|
-
new Error(
|
|
115
|
-
`Performing action "${event.type}" failed due to: ${error.message}`,
|
|
116
|
-
),
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
|
|
123
106
|
if (!defaultAction) {
|
|
124
107
|
return
|
|
125
108
|
}
|
|
@@ -133,7 +116,6 @@ export function performEvent({
|
|
|
133
116
|
},
|
|
134
117
|
action: defaultAction,
|
|
135
118
|
})
|
|
136
|
-
editor.onChange()
|
|
137
119
|
} catch (error) {
|
|
138
120
|
console.error(
|
|
139
121
|
new Error(
|
|
@@ -142,6 +124,9 @@ export function performEvent({
|
|
|
142
124
|
)
|
|
143
125
|
}
|
|
144
126
|
})
|
|
127
|
+
|
|
128
|
+
editor.onChange()
|
|
129
|
+
|
|
145
130
|
return
|
|
146
131
|
}
|
|
147
132
|
|
|
@@ -196,7 +181,6 @@ export function performEvent({
|
|
|
196
181
|
keyGenerator,
|
|
197
182
|
schema,
|
|
198
183
|
getSnapshot,
|
|
199
|
-
defaultActionCallback: undefined,
|
|
200
184
|
nativeEvent: undefined,
|
|
201
185
|
})
|
|
202
186
|
|
|
@@ -218,26 +202,39 @@ export function performEvent({
|
|
|
218
202
|
keyGenerator,
|
|
219
203
|
schema,
|
|
220
204
|
getSnapshot,
|
|
221
|
-
defaultActionCallback: undefined,
|
|
222
205
|
nativeEvent: undefined,
|
|
223
206
|
})
|
|
224
207
|
} else {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
208
|
+
const internalAction = {
|
|
209
|
+
...action.event,
|
|
210
|
+
editor,
|
|
211
|
+
}
|
|
212
|
+
let actionFailed = false
|
|
213
|
+
|
|
214
|
+
withApplyingBehaviorActions(editor, () => {
|
|
215
|
+
try {
|
|
216
|
+
performAction({
|
|
217
|
+
context: {
|
|
218
|
+
keyGenerator,
|
|
219
|
+
schema,
|
|
220
|
+
},
|
|
221
|
+
action: internalAction,
|
|
222
|
+
})
|
|
223
|
+
} catch (error) {
|
|
224
|
+
console.error(
|
|
225
|
+
new Error(
|
|
226
|
+
`Performing action "${action.event.type}" as a result of "${event.type}" failed due to: ${error.message}`,
|
|
227
|
+
),
|
|
228
|
+
)
|
|
229
|
+
actionFailed = true
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
if (actionFailed) {
|
|
239
234
|
break
|
|
240
235
|
}
|
|
236
|
+
|
|
237
|
+
editor.onChange()
|
|
241
238
|
}
|
|
242
239
|
|
|
243
240
|
continue
|
|
@@ -247,25 +244,33 @@ export function performEvent({
|
|
|
247
244
|
...action,
|
|
248
245
|
editor,
|
|
249
246
|
}
|
|
247
|
+
let actionFailed = false
|
|
250
248
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
249
|
+
withApplyingBehaviorActions(editor, () => {
|
|
250
|
+
try {
|
|
251
|
+
performAction({
|
|
252
|
+
context: {
|
|
253
|
+
keyGenerator,
|
|
254
|
+
schema,
|
|
255
|
+
},
|
|
256
|
+
action: internalAction,
|
|
257
|
+
})
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(
|
|
260
|
+
new Error(
|
|
261
|
+
`Performing action "${internalAction.type}" as a result of "${event.type}" failed due to: ${error.message}`,
|
|
262
|
+
),
|
|
263
|
+
)
|
|
264
|
+
actionFailed = true
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
if (actionFailed) {
|
|
265
269
|
break
|
|
266
270
|
}
|
|
271
|
+
|
|
272
|
+
editor.onChange()
|
|
267
273
|
}
|
|
268
|
-
editor.onChange()
|
|
269
274
|
})
|
|
270
275
|
}
|
|
271
276
|
|
|
@@ -276,21 +281,6 @@ export function performEvent({
|
|
|
276
281
|
}
|
|
277
282
|
|
|
278
283
|
if (!behaviorOverwritten) {
|
|
279
|
-
if (defaultActionCallback) {
|
|
280
|
-
withApplyingBehaviorActions(editor, () => {
|
|
281
|
-
try {
|
|
282
|
-
defaultActionCallback()
|
|
283
|
-
} catch (error) {
|
|
284
|
-
console.error(
|
|
285
|
-
new Error(
|
|
286
|
-
`Performing "${event.type}" failed due to: ${error.message}`,
|
|
287
|
-
),
|
|
288
|
-
)
|
|
289
|
-
}
|
|
290
|
-
})
|
|
291
|
-
return
|
|
292
|
-
}
|
|
293
|
-
|
|
294
284
|
if (!defaultAction) {
|
|
295
285
|
return
|
|
296
286
|
}
|
|
@@ -304,7 +294,6 @@ export function performEvent({
|
|
|
304
294
|
},
|
|
305
295
|
action: defaultAction,
|
|
306
296
|
})
|
|
307
|
-
editor.onChange()
|
|
308
297
|
} catch (error) {
|
|
309
298
|
console.error(
|
|
310
299
|
new Error(
|
|
@@ -313,5 +302,6 @@ export function performEvent({
|
|
|
313
302
|
)
|
|
314
303
|
}
|
|
315
304
|
})
|
|
305
|
+
editor.onChange()
|
|
316
306
|
}
|
|
317
307
|
}
|
|
@@ -32,7 +32,7 @@ type NamespacedBehaviorEventType<
|
|
|
32
32
|
* External events
|
|
33
33
|
**************************************/
|
|
34
34
|
|
|
35
|
-
type ExternalBehaviorEventNamespace = 'insert'
|
|
35
|
+
type ExternalBehaviorEventNamespace = 'blur' | 'focus' | 'insert'
|
|
36
36
|
|
|
37
37
|
type ExternalBehaviorEventType<
|
|
38
38
|
TNamespace extends ExternalBehaviorEventNamespace,
|
|
@@ -40,6 +40,12 @@ type ExternalBehaviorEventType<
|
|
|
40
40
|
> = TType extends '' ? `${TNamespace}` : `${TNamespace}.${TType}`
|
|
41
41
|
|
|
42
42
|
export type ExternalBehaviorEvent =
|
|
43
|
+
| {
|
|
44
|
+
type: ExternalBehaviorEventType<'blur'>
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
type: ExternalBehaviorEventType<'focus'>
|
|
48
|
+
}
|
|
43
49
|
| {
|
|
44
50
|
type: ExternalBehaviorEventType<'insert', 'block object'>
|
|
45
51
|
placement: InsertPlacement
|
|
@@ -61,14 +67,12 @@ const syntheticBehaviorEventTypes = [
|
|
|
61
67
|
'annotation.remove',
|
|
62
68
|
'block.set',
|
|
63
69
|
'block.unset',
|
|
64
|
-
'blur',
|
|
65
70
|
'decorator.add',
|
|
66
71
|
'decorator.remove',
|
|
67
72
|
'delete',
|
|
68
73
|
'delete.backward',
|
|
69
74
|
'delete.block',
|
|
70
75
|
'delete.forward',
|
|
71
|
-
'focus',
|
|
72
76
|
'history.redo',
|
|
73
77
|
'history.undo',
|
|
74
78
|
'insert.inline object',
|
|
@@ -114,9 +118,6 @@ export type SyntheticBehaviorEvent =
|
|
|
114
118
|
at: [KeyedSegment]
|
|
115
119
|
props: Array<string>
|
|
116
120
|
}
|
|
117
|
-
| {
|
|
118
|
-
type: StrictExtract<SyntheticBehaviorEventType, 'blur'>
|
|
119
|
-
}
|
|
120
121
|
| {
|
|
121
122
|
type: StrictExtract<SyntheticBehaviorEventType, 'decorator.add'>
|
|
122
123
|
decorator: string
|
|
@@ -145,9 +146,6 @@ export type SyntheticBehaviorEvent =
|
|
|
145
146
|
type: StrictExtract<SyntheticBehaviorEventType, 'delete.forward'>
|
|
146
147
|
unit: TextUnit
|
|
147
148
|
}
|
|
148
|
-
| {
|
|
149
|
-
type: StrictExtract<SyntheticBehaviorEventType, 'focus'>
|
|
150
|
-
}
|
|
151
149
|
| {
|
|
152
150
|
type: StrictExtract<SyntheticBehaviorEventType, 'history.redo'>
|
|
153
151
|
}
|
package/src/editor/Editable.tsx
CHANGED
|
@@ -51,7 +51,7 @@ import type {
|
|
|
51
51
|
ScrollSelectionIntoViewFunction,
|
|
52
52
|
} from '../types/editor'
|
|
53
53
|
import type {HotkeyOptions} from '../types/options'
|
|
54
|
-
import {
|
|
54
|
+
import {isSelectionCollapsed} from '../utils'
|
|
55
55
|
import {getSelectionEndPoint} from '../utils/util.get-selection-end-point'
|
|
56
56
|
import {Element} from './components/Element'
|
|
57
57
|
import {Leaf} from './components/Leaf'
|
|
@@ -570,17 +570,9 @@ export const PortableTextEditable = forwardRef<
|
|
|
570
570
|
onFocus(event)
|
|
571
571
|
}
|
|
572
572
|
if (!event.isDefaultPrevented()) {
|
|
573
|
-
const selectionBefore = slateEditor.selection
|
|
574
|
-
? slateRangeToSelection({
|
|
575
|
-
schema: editorActor.getSnapshot().context.schema,
|
|
576
|
-
editor: slateEditor,
|
|
577
|
-
range: slateEditor.selection,
|
|
578
|
-
})
|
|
579
|
-
: null
|
|
580
|
-
|
|
581
573
|
editorActor.send({type: 'notify.focused', event})
|
|
582
574
|
|
|
583
|
-
const
|
|
575
|
+
const selection = slateEditor.selection
|
|
584
576
|
? slateRangeToSelection({
|
|
585
577
|
schema: editorActor.getSnapshot().context.schema,
|
|
586
578
|
editor: slateEditor,
|
|
@@ -588,15 +580,10 @@ export const PortableTextEditable = forwardRef<
|
|
|
588
580
|
})
|
|
589
581
|
: null
|
|
590
582
|
|
|
591
|
-
if (
|
|
592
|
-
selectionBefore &&
|
|
593
|
-
selectionAfter &&
|
|
594
|
-
isEqualSelections(selectionBefore, selectionAfter)
|
|
595
|
-
) {
|
|
596
|
-
// If the selection is the same, emit it explicitly here as there is no actual onChange event triggered.
|
|
583
|
+
if (selection) {
|
|
597
584
|
editorActor.send({
|
|
598
585
|
type: 'notify.selection',
|
|
599
|
-
selection
|
|
586
|
+
selection,
|
|
600
587
|
})
|
|
601
588
|
}
|
|
602
589
|
}
|
|
@@ -191,6 +191,20 @@ function createInternalEditorFromActor(
|
|
|
191
191
|
editorActor.send(event)
|
|
192
192
|
break
|
|
193
193
|
|
|
194
|
+
case 'blur':
|
|
195
|
+
editorActor.send({
|
|
196
|
+
type: 'blur',
|
|
197
|
+
editor: slateEditor.instance,
|
|
198
|
+
})
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
case 'focus':
|
|
202
|
+
editorActor.send({
|
|
203
|
+
type: 'focus',
|
|
204
|
+
editor: slateEditor.instance,
|
|
205
|
+
})
|
|
206
|
+
break
|
|
207
|
+
|
|
194
208
|
case 'insert.block object':
|
|
195
209
|
editorActor.send({
|
|
196
210
|
type: 'behavior event',
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {Patch} from '@portabletext/patches'
|
|
2
2
|
import type {PortableTextBlock} from '@sanity/types'
|
|
3
3
|
import type {FocusEvent} from 'react'
|
|
4
|
+
import {Transforms} from 'slate'
|
|
5
|
+
import {ReactEditor} from 'slate-react'
|
|
4
6
|
import {
|
|
5
7
|
assertEvent,
|
|
6
8
|
assign,
|
|
@@ -161,6 +163,14 @@ export type HasTag = ReturnType<EditorActor['getSnapshot']>['hasTag']
|
|
|
161
163
|
*/
|
|
162
164
|
export type InternalEditorEvent =
|
|
163
165
|
| ExternalEditorEvent
|
|
166
|
+
| {
|
|
167
|
+
type: 'blur'
|
|
168
|
+
editor: PortableTextSlateEditor
|
|
169
|
+
}
|
|
170
|
+
| {
|
|
171
|
+
type: 'focus'
|
|
172
|
+
editor: PortableTextSlateEditor
|
|
173
|
+
}
|
|
164
174
|
| {
|
|
165
175
|
type: 'normalizing'
|
|
166
176
|
}
|
|
@@ -174,7 +184,6 @@ export type InternalEditorEvent =
|
|
|
174
184
|
type: 'behavior event'
|
|
175
185
|
behaviorEvent: BehaviorEvent
|
|
176
186
|
editor: PortableTextSlateEditor
|
|
177
|
-
defaultActionCallback?: () => void
|
|
178
187
|
nativeEvent?: {preventDefault: () => void}
|
|
179
188
|
}
|
|
180
189
|
| MutationEvent
|
|
@@ -217,6 +226,7 @@ export const editorMachine = setup({
|
|
|
217
226
|
ghost?: HTMLElement
|
|
218
227
|
origin: Pick<EventPosition, 'selection'>
|
|
219
228
|
}
|
|
229
|
+
slateEditor?: PortableTextSlateEditor
|
|
220
230
|
},
|
|
221
231
|
events: {} as InternalEditorEvent,
|
|
222
232
|
emitted: {} as InternalEditorEmittedEvent,
|
|
@@ -292,6 +302,31 @@ export const editorMachine = setup({
|
|
|
292
302
|
'clear pending events': assign({
|
|
293
303
|
pendingEvents: [],
|
|
294
304
|
}),
|
|
305
|
+
'handle blur': ({event}) => {
|
|
306
|
+
assertEvent(event, 'blur')
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
ReactEditor.blur(event.editor)
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.error(new Error(`Failed to blur editor: ${error.message}`))
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
'handle focus': ({context}) => {
|
|
315
|
+
if (!context.slateEditor) {
|
|
316
|
+
console.error('No Slate editor found to focus')
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
const currentSelection = context.slateEditor.selection
|
|
322
|
+
ReactEditor.focus(context.slateEditor)
|
|
323
|
+
if (currentSelection) {
|
|
324
|
+
Transforms.select(context.slateEditor, currentSelection)
|
|
325
|
+
}
|
|
326
|
+
} catch (error) {
|
|
327
|
+
console.error(new Error(`Failed to focus editor: ${error.message}`))
|
|
328
|
+
}
|
|
329
|
+
},
|
|
295
330
|
'handle behavior event': ({context, event, self}) => {
|
|
296
331
|
assertEvent(event, ['behavior event'])
|
|
297
332
|
|
|
@@ -313,13 +348,18 @@ export const editorMachine = setup({
|
|
|
313
348
|
internalDrag: context.internalDrag,
|
|
314
349
|
}),
|
|
315
350
|
nativeEvent: event.nativeEvent,
|
|
316
|
-
defaultActionCallback:
|
|
317
|
-
event.type === 'behavior event'
|
|
318
|
-
? event.defaultActionCallback
|
|
319
|
-
: undefined,
|
|
320
351
|
})
|
|
321
352
|
},
|
|
322
353
|
},
|
|
354
|
+
guards: {
|
|
355
|
+
'slate is busy': ({context}) => {
|
|
356
|
+
if (!context.slateEditor) {
|
|
357
|
+
return false
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return context.slateEditor.operations.length > 0
|
|
361
|
+
},
|
|
362
|
+
},
|
|
323
363
|
}).createMachine({
|
|
324
364
|
id: 'editor',
|
|
325
365
|
context: ({input}) => ({
|
|
@@ -426,6 +466,13 @@ export const editorMachine = setup({
|
|
|
426
466
|
'behavior event': {
|
|
427
467
|
actions: 'handle behavior event',
|
|
428
468
|
},
|
|
469
|
+
'blur': {
|
|
470
|
+
actions: 'handle blur',
|
|
471
|
+
},
|
|
472
|
+
'focus': {
|
|
473
|
+
target: '.focusing',
|
|
474
|
+
actions: [assign({slateEditor: ({event}) => event.editor})],
|
|
475
|
+
},
|
|
429
476
|
},
|
|
430
477
|
initial: 'idle',
|
|
431
478
|
states: {
|
|
@@ -444,6 +491,30 @@ export const editorMachine = setup({
|
|
|
444
491
|
},
|
|
445
492
|
},
|
|
446
493
|
},
|
|
494
|
+
'focusing': {
|
|
495
|
+
initial: 'checking if busy',
|
|
496
|
+
states: {
|
|
497
|
+
'checking if busy': {
|
|
498
|
+
always: [
|
|
499
|
+
{
|
|
500
|
+
guard: 'slate is busy',
|
|
501
|
+
target: 'busy',
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
target: '#editor.edit mode.editable.idle',
|
|
505
|
+
actions: ['handle focus'],
|
|
506
|
+
},
|
|
507
|
+
],
|
|
508
|
+
},
|
|
509
|
+
'busy': {
|
|
510
|
+
after: {
|
|
511
|
+
10: {
|
|
512
|
+
target: 'checking if busy',
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
447
518
|
'dragging internally': {
|
|
448
519
|
exit: [
|
|
449
520
|
({context}) => {
|
|
@@ -116,9 +116,6 @@ export function createWithEventListeners(editorActor: EditorActor) {
|
|
|
116
116
|
text,
|
|
117
117
|
},
|
|
118
118
|
editor,
|
|
119
|
-
defaultActionCallback: () => {
|
|
120
|
-
insertText(text, options)
|
|
121
|
-
},
|
|
122
119
|
})
|
|
123
120
|
return
|
|
124
121
|
}
|
|
@@ -167,9 +164,6 @@ export function createWithEventListeners(editorActor: EditorActor) {
|
|
|
167
164
|
}),
|
|
168
165
|
},
|
|
169
166
|
editor,
|
|
170
|
-
defaultActionCallback: () => {
|
|
171
|
-
select(location)
|
|
172
|
-
},
|
|
173
167
|
})
|
|
174
168
|
return
|
|
175
169
|
}
|
|
@@ -49,19 +49,13 @@ export function createEditableAPI(
|
|
|
49
49
|
const editableApi: EditableAPI = {
|
|
50
50
|
focus: (): void => {
|
|
51
51
|
editorActor.send({
|
|
52
|
-
type: '
|
|
53
|
-
behaviorEvent: {
|
|
54
|
-
type: 'focus',
|
|
55
|
-
},
|
|
52
|
+
type: 'focus',
|
|
56
53
|
editor,
|
|
57
54
|
})
|
|
58
55
|
},
|
|
59
56
|
blur: (): void => {
|
|
60
57
|
editorActor.send({
|
|
61
|
-
type: '
|
|
62
|
-
behaviorEvent: {
|
|
63
|
-
type: 'blur',
|
|
64
|
-
},
|
|
58
|
+
type: 'blur',
|
|
65
59
|
editor,
|
|
66
60
|
})
|
|
67
61
|
},
|
|
@@ -28,7 +28,7 @@ export function withApplyingBehaviorActionSet(editor: Editor, fn: () => void) {
|
|
|
28
28
|
const current = CURRENT_BEHAVIOR_ACTION_SET.get(editor)
|
|
29
29
|
|
|
30
30
|
if (current) {
|
|
31
|
-
|
|
31
|
+
fn()
|
|
32
32
|
return
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -38,7 +38,7 @@ export function withApplyingBehaviorActionSet(editor: Editor, fn: () => void) {
|
|
|
38
38
|
actionSetId: defaultKeyGenerator(),
|
|
39
39
|
},
|
|
40
40
|
)
|
|
41
|
-
|
|
41
|
+
fn()
|
|
42
42
|
CURRENT_BEHAVIOR_ACTION_SET.set(editor, undefined)
|
|
43
43
|
}
|
|
44
44
|
|