@portabletext/editor 1.40.3 → 1.40.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 +66 -33
- package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
- package/lib/_chunks-cjs/util.is-selection-collapsed.cjs +6 -0
- package/lib/_chunks-cjs/util.is-selection-collapsed.cjs.map +1 -0
- package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
- package/lib/_chunks-es/editor-provider.js +67 -34
- package/lib/_chunks-es/editor-provider.js.map +1 -1
- package/lib/_chunks-es/util.is-selection-collapsed.js +7 -0
- package/lib/_chunks-es/util.is-selection-collapsed.js.map +1 -0
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
- package/lib/index.cjs +47 -13
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +49 -14
- package/lib/index.js.map +1 -1
- package/lib/utils/index.cjs +2 -5
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.cts +1 -2
- package/lib/utils/index.d.ts +1 -2
- package/lib/utils/index.js +1 -3
- package/lib/utils/index.js.map +1 -1
- package/package.json +3 -3
- package/src/behavior-actions/behavior.action.insert-blocks.ts +5 -1
- package/src/internal-utils/drag-selection.test.ts +74 -1
- package/src/internal-utils/drag-selection.ts +20 -4
- package/src/internal-utils/event-position.ts +38 -7
- package/src/internal-utils/slate-utils.ts +60 -1
- package/src/utils/util.is-keyed-segment.ts +2 -2
package/lib/utils/index.cjs
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var util_sliceBlocks = require("../_chunks-cjs/util.slice-blocks.cjs"), util_selectionPointToBlockOffset = require("../_chunks-cjs/util.selection-point-to-block-offset.cjs"), util_mergeTextBlocks = require("../_chunks-cjs/util.merge-text-blocks.cjs");
|
|
3
|
+
var util_sliceBlocks = require("../_chunks-cjs/util.slice-blocks.cjs"), util_selectionPointToBlockOffset = require("../_chunks-cjs/util.selection-point-to-block-offset.cjs"), util_isSelectionCollapsed = require("../_chunks-cjs/util.is-selection-collapsed.cjs"), util_mergeTextBlocks = require("../_chunks-cjs/util.merge-text-blocks.cjs");
|
|
4
4
|
function isEqualSelections(a, b) {
|
|
5
5
|
return !a && !b ? !0 : !a || !b ? !1 : util_sliceBlocks.isEqualSelectionPoints(a.anchor, b.anchor) && util_sliceBlocks.isEqualSelectionPoints(a.focus, b.focus);
|
|
6
6
|
}
|
|
7
|
-
function isSelectionCollapsed(selection) {
|
|
8
|
-
return selection ? selection.anchor.path.join() === selection.focus.path.join() && selection.anchor.offset === selection.focus.offset : !1;
|
|
9
|
-
}
|
|
10
7
|
function splitTextBlock({
|
|
11
8
|
context,
|
|
12
9
|
block,
|
|
@@ -64,9 +61,9 @@ exports.blockOffsetToSelectionPoint = util_selectionPointToBlockOffset.blockOffs
|
|
|
64
61
|
exports.blockOffsetsToSelection = util_selectionPointToBlockOffset.blockOffsetsToSelection;
|
|
65
62
|
exports.childSelectionPointToBlockOffset = util_selectionPointToBlockOffset.childSelectionPointToBlockOffset;
|
|
66
63
|
exports.selectionPointToBlockOffset = util_selectionPointToBlockOffset.selectionPointToBlockOffset;
|
|
64
|
+
exports.isSelectionCollapsed = util_isSelectionCollapsed.isSelectionCollapsed;
|
|
67
65
|
exports.isTextBlock = util_mergeTextBlocks.isTextBlock;
|
|
68
66
|
exports.mergeTextBlocks = util_mergeTextBlocks.mergeTextBlocks;
|
|
69
67
|
exports.isEqualSelections = isEqualSelections;
|
|
70
|
-
exports.isSelectionCollapsed = isSelectionCollapsed;
|
|
71
68
|
exports.splitTextBlock = splitTextBlock;
|
|
72
69
|
//# sourceMappingURL=index.cjs.map
|
package/lib/utils/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["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":["isEqualSelections","a","b","isEqualSelectionPoints","anchor","focus","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceBlocks","blocks","selection","path","_key","offset","after","isSpan","text","isTextBlock"],"mappings":";;;AAMgBA,SAAAA,kBAAkBC,GAAoBC,GAAoB;AACpE,SAAA,CAACD,KAAK,CAACC,IACF,KAGL,CAACD,KAAK,CAACC,IACF,KAIPC,iBAAAA,uBAAuBF,EAAEG,QAAQF,EAAEE,MAAM,KACzCD,wCAAuBF,EAAEI,OAAOH,EAAEG,KAAK;AAE3C;ACTO,SAASC,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,iBAAAA,YAAY;AAAA,IACzBC,QAAQ,CAACT,KAAK;AAAA,IACdU,WAAW;AAAA,MACTd,QAAQ;AAAA,QACNe,MAAM,CAAC;AAAA,UAACC,MAAMZ,MAAMY;AAAAA,WAAO,YAAY;AAAA,UAACA,MAAMV,WAAWU;AAAAA,QAAAA,CAAK;AAAA,QAC9DC,QAAQ;AAAA,MACV;AAAA,MACAhB,OAAOI;AAAAA,IAAAA;AAAAA,EAEV,CAAA,EAAEG,GAAG,CAAC,GACDU,QAAQN,iBAAAA,YAAY;AAAA,IACxBC,QAAQ,CAACT,KAAK;AAAA,IACdU,WAAW;AAAA,MACTd,QAAQK;AAAAA,MACRJ,OAAO;AAAA,QACLc,MAAM,CAAC;AAAA,UAACC,MAAMZ,MAAMY;AAAAA,WAAO,YAAY;AAAA,UAACA,MAAMP,UAAUO;AAAAA,QAAAA,CAAK;AAAA,QAC7DC,QAAQE,iBAAOhB,OAAAA,SAASM,SAAS,IAAIA,UAAUW,KAAKV,SAAS;AAAA,MAAA;AAAA,IAC/D;AAAA,EACF,CACD,EAAEF,GAAG,CAAC;AAEP,MAAI,EAACG,CAAAA,UAAU,CAACO,UAIZ,EAACG,CAAAA,qBAAAA,YAAYlB,SAASQ,MAAM,KAAK,CAACU,qBAAYlB,YAAAA,SAASe,KAAK;AAIzD,WAAA;AAAA,MAACP;AAAAA,MAAQO;AAAAA,IAAK;AACvB;;;;;;;;;;;;;;;;;;;;;;"}
|
package/lib/utils/index.d.cts
CHANGED
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
BlockStyleDefinition,
|
|
7
7
|
ObjectSchemaType,
|
|
8
8
|
Path,
|
|
9
|
-
PathSegment,
|
|
10
9
|
PortableTextChild,
|
|
11
10
|
PortableTextListBlock,
|
|
12
11
|
PortableTextTextBlock,
|
|
@@ -22139,7 +22138,7 @@ export declare function isEqualSelections(
|
|
|
22139
22138
|
* @public
|
|
22140
22139
|
*/
|
|
22141
22140
|
export declare function isKeyedSegment(
|
|
22142
|
-
segment:
|
|
22141
|
+
segment: unknown,
|
|
22143
22142
|
): segment is KeyedSegment
|
|
22144
22143
|
|
|
22145
22144
|
/**
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
BlockStyleDefinition,
|
|
7
7
|
ObjectSchemaType,
|
|
8
8
|
Path,
|
|
9
|
-
PathSegment,
|
|
10
9
|
PortableTextChild,
|
|
11
10
|
PortableTextListBlock,
|
|
12
11
|
PortableTextTextBlock,
|
|
@@ -22139,7 +22138,7 @@ export declare function isEqualSelections(
|
|
|
22139
22138
|
* @public
|
|
22140
22139
|
*/
|
|
22141
22140
|
export declare function isKeyedSegment(
|
|
22142
|
-
segment:
|
|
22141
|
+
segment: unknown,
|
|
22143
22142
|
): segment is KeyedSegment
|
|
22144
22143
|
|
|
22145
22144
|
/**
|
package/lib/utils/index.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { isEqualSelectionPoints, sliceBlocks, isSpan } from "../_chunks-es/util.slice-blocks.js";
|
|
2
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 { isSelectionCollapsed } from "../_chunks-es/util.is-selection-collapsed.js";
|
|
4
5
|
import { isTextBlock } from "../_chunks-es/util.merge-text-blocks.js";
|
|
5
6
|
import { mergeTextBlocks } from "../_chunks-es/util.merge-text-blocks.js";
|
|
6
7
|
function isEqualSelections(a, b) {
|
|
7
8
|
return !a && !b ? !0 : !a || !b ? !1 : isEqualSelectionPoints(a.anchor, b.anchor) && isEqualSelectionPoints(a.focus, b.focus);
|
|
8
9
|
}
|
|
9
|
-
function isSelectionCollapsed(selection) {
|
|
10
|
-
return selection ? selection.anchor.path.join() === selection.focus.path.join() && selection.anchor.offset === selection.focus.offset : !1;
|
|
11
|
-
}
|
|
12
10
|
function splitTextBlock({
|
|
13
11
|
context,
|
|
14
12
|
block,
|
package/lib/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["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":["isEqualSelections","a","b","isEqualSelectionPoints","anchor","focus","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceBlocks","blocks","selection","path","_key","offset","after","isSpan","text","isTextBlock"],"mappings":";;;;;;AAMgBA,SAAAA,kBAAkBC,GAAoBC,GAAoB;AACpE,SAAA,CAACD,KAAK,CAACC,IACF,KAGL,CAACD,KAAK,CAACC,IACF,KAIPC,uBAAuBF,EAAEG,QAAQF,EAAEE,MAAM,KACzCD,uBAAuBF,EAAEI,OAAOH,EAAEG,KAAK;AAE3C;ACTO,SAASC,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,IACdU,WAAW;AAAA,MACTd,QAAQ;AAAA,QACNe,MAAM,CAAC;AAAA,UAACC,MAAMZ,MAAMY;AAAAA,WAAO,YAAY;AAAA,UAACA,MAAMV,WAAWU;AAAAA,QAAAA,CAAK;AAAA,QAC9DC,QAAQ;AAAA,MACV;AAAA,MACAhB,OAAOI;AAAAA,IAAAA;AAAAA,EAEV,CAAA,EAAEG,GAAG,CAAC,GACDU,QAAQN,YAAY;AAAA,IACxBC,QAAQ,CAACT,KAAK;AAAA,IACdU,WAAW;AAAA,MACTd,QAAQK;AAAAA,MACRJ,OAAO;AAAA,QACLc,MAAM,CAAC;AAAA,UAACC,MAAMZ,MAAMY;AAAAA,WAAO,YAAY;AAAA,UAACA,MAAMP,UAAUO;AAAAA,QAAAA,CAAK;AAAA,QAC7DC,QAAQE,OAAOhB,SAASM,SAAS,IAAIA,UAAUW,KAAKV,SAAS;AAAA,MAAA;AAAA,IAC/D;AAAA,EACF,CACD,EAAEF,GAAG,CAAC;AAEP,MAAI,EAACG,CAAAA,UAAU,CAACO,UAIZ,EAACG,CAAAA,YAAYlB,SAASQ,MAAM,KAAK,CAACU,YAAYlB,SAASe,KAAK;AAIzD,WAAA;AAAA,MAACP;AAAAA,MAAQO;AAAAA,IAAK;AACvB;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.40.
|
|
3
|
+
"version": "1.40.4",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
"slate-react": "0.112.1",
|
|
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.14"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@portabletext/toolkit": "^2.0.17",
|
|
@@ -122,14 +122,18 @@ export const insertBlocksActionImplementation: BehaviorActionImplementation<
|
|
|
122
122
|
index++
|
|
123
123
|
}
|
|
124
124
|
} else {
|
|
125
|
+
let index = 0
|
|
126
|
+
|
|
125
127
|
for (const block of fragment) {
|
|
126
128
|
insertBlock({
|
|
127
129
|
block,
|
|
128
|
-
placement: 'auto',
|
|
130
|
+
placement: index === 0 ? 'auto' : 'after',
|
|
129
131
|
select: 'end',
|
|
130
132
|
editor: action.editor,
|
|
131
133
|
schema: context.schema,
|
|
132
134
|
})
|
|
135
|
+
|
|
136
|
+
index++
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
}
|
|
@@ -41,10 +41,11 @@ describe(getDragSelection.name, () => {
|
|
|
41
41
|
{
|
|
42
42
|
_key: keyGenerator(),
|
|
43
43
|
_type: 'span',
|
|
44
|
-
text: '
|
|
44
|
+
text: 'baz',
|
|
45
45
|
},
|
|
46
46
|
],
|
|
47
47
|
}
|
|
48
|
+
const bazPath = [{_key: baz._key}, 'children', {_key: baz.children[0]._key}]
|
|
48
49
|
const image = {
|
|
49
50
|
_key: keyGenerator(),
|
|
50
51
|
_type: 'image',
|
|
@@ -262,6 +263,78 @@ describe(getDragSelection.name, () => {
|
|
|
262
263
|
})
|
|
263
264
|
})
|
|
264
265
|
|
|
266
|
+
test('dragging two text blocks with the top drag handle', () => {
|
|
267
|
+
expect(
|
|
268
|
+
getDragSelection({
|
|
269
|
+
eventSelection: {
|
|
270
|
+
anchor: {
|
|
271
|
+
path: fooPath,
|
|
272
|
+
offset: 0,
|
|
273
|
+
},
|
|
274
|
+
focus: {
|
|
275
|
+
path: fooPath,
|
|
276
|
+
offset: 0,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
snapshot: snapshot({
|
|
280
|
+
anchor: {
|
|
281
|
+
path: fooPath,
|
|
282
|
+
offset: 1,
|
|
283
|
+
},
|
|
284
|
+
focus: {
|
|
285
|
+
path: bazPath,
|
|
286
|
+
offset: 3,
|
|
287
|
+
},
|
|
288
|
+
}),
|
|
289
|
+
}),
|
|
290
|
+
).toEqual({
|
|
291
|
+
anchor: {
|
|
292
|
+
path: fooPath,
|
|
293
|
+
offset: 0,
|
|
294
|
+
},
|
|
295
|
+
focus: {
|
|
296
|
+
path: bazPath,
|
|
297
|
+
offset: 3,
|
|
298
|
+
},
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
test('dragging two text blocks with the bottom drag handle', () => {
|
|
303
|
+
expect(
|
|
304
|
+
getDragSelection({
|
|
305
|
+
eventSelection: {
|
|
306
|
+
anchor: {
|
|
307
|
+
path: bazPath,
|
|
308
|
+
offset: 0,
|
|
309
|
+
},
|
|
310
|
+
focus: {
|
|
311
|
+
path: bazPath,
|
|
312
|
+
offset: 0,
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
snapshot: snapshot({
|
|
316
|
+
anchor: {
|
|
317
|
+
path: fooPath,
|
|
318
|
+
offset: 1,
|
|
319
|
+
},
|
|
320
|
+
focus: {
|
|
321
|
+
path: bazPath,
|
|
322
|
+
offset: 3,
|
|
323
|
+
},
|
|
324
|
+
}),
|
|
325
|
+
}),
|
|
326
|
+
).toEqual({
|
|
327
|
+
anchor: {
|
|
328
|
+
path: fooPath,
|
|
329
|
+
offset: 0,
|
|
330
|
+
},
|
|
331
|
+
focus: {
|
|
332
|
+
path: bazPath,
|
|
333
|
+
offset: 3,
|
|
334
|
+
},
|
|
335
|
+
})
|
|
336
|
+
})
|
|
337
|
+
|
|
265
338
|
test('dragging a block object with an expanded selected', () => {
|
|
266
339
|
expect(
|
|
267
340
|
getDragSelection({
|
|
@@ -48,16 +48,32 @@ export function getDragSelection({
|
|
|
48
48
|
if (
|
|
49
49
|
snapshot.context.selection &&
|
|
50
50
|
selectors.isSelectionExpanded(snapshot) &&
|
|
51
|
-
selectors.isOverlappingSelection(eventSelection)(snapshot) &&
|
|
52
51
|
selectedBlocks.length > 1
|
|
53
52
|
) {
|
|
54
53
|
const selectionStartBlock = selectors.getSelectionStartBlock(snapshot)
|
|
55
54
|
const selectionEndBlock = selectors.getSelectionEndBlock(snapshot)
|
|
56
55
|
|
|
57
|
-
if (selectionStartBlock
|
|
56
|
+
if (!selectionStartBlock || !selectionEndBlock) {
|
|
57
|
+
return dragSelection
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const selectionStartPoint = utils.getBlockStartPoint(selectionStartBlock)
|
|
61
|
+
const selectionEndPoint = utils.getBlockEndPoint(selectionEndBlock)
|
|
62
|
+
|
|
63
|
+
const eventSelectionInsideBlocks = selectors.isOverlappingSelection(
|
|
64
|
+
eventSelection,
|
|
65
|
+
)({
|
|
66
|
+
...snapshot,
|
|
67
|
+
context: {
|
|
68
|
+
...snapshot.context,
|
|
69
|
+
selection: {anchor: selectionStartPoint, focus: selectionEndPoint},
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
if (eventSelectionInsideBlocks) {
|
|
58
74
|
dragSelection = {
|
|
59
|
-
anchor:
|
|
60
|
-
focus:
|
|
75
|
+
anchor: selectionStartPoint,
|
|
76
|
+
focus: selectionEndPoint,
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
}
|
|
@@ -4,6 +4,7 @@ import type {EditorSchema, EditorSelection} from '..'
|
|
|
4
4
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
5
5
|
import * as utils from '../utils'
|
|
6
6
|
import {toPortableTextRange} from './ranges'
|
|
7
|
+
import {getNodeBlock} from './slate-utils'
|
|
7
8
|
import {fromSlateValue} from './values'
|
|
8
9
|
|
|
9
10
|
export type EventPosition = {
|
|
@@ -31,6 +32,12 @@ export function getEventPosition({
|
|
|
31
32
|
return undefined
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
const block = getNodeBlock({
|
|
36
|
+
editor: slateEditor,
|
|
37
|
+
schema,
|
|
38
|
+
node,
|
|
39
|
+
})
|
|
40
|
+
|
|
34
41
|
const positionBlock = getEventPositionBlock({node, slateEditor, event})
|
|
35
42
|
const selection = getEventSelection({
|
|
36
43
|
schema,
|
|
@@ -38,13 +45,7 @@ export function getEventPosition({
|
|
|
38
45
|
event,
|
|
39
46
|
})
|
|
40
47
|
|
|
41
|
-
if (positionBlock && !selection && !Editor.isEditor(node)) {
|
|
42
|
-
const block = fromSlateValue([node], schema.block.name)?.at(0)
|
|
43
|
-
|
|
44
|
-
if (!block) {
|
|
45
|
-
return undefined
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
+
if (block && positionBlock && !selection && !Editor.isEditor(node)) {
|
|
48
49
|
return {
|
|
49
50
|
block: positionBlock,
|
|
50
51
|
isEditor: false,
|
|
@@ -65,6 +66,36 @@ export function getEventPosition({
|
|
|
65
66
|
return undefined
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
const focusBlockPath = selection.focus.path.at(0)
|
|
70
|
+
const focusBlockKey = utils.isKeyedSegment(focusBlockPath)
|
|
71
|
+
? focusBlockPath._key
|
|
72
|
+
: undefined
|
|
73
|
+
|
|
74
|
+
if (!focusBlockKey) {
|
|
75
|
+
return undefined
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
utils.isSelectionCollapsed(selection) &&
|
|
80
|
+
block &&
|
|
81
|
+
focusBlockKey !== block._key
|
|
82
|
+
) {
|
|
83
|
+
return {
|
|
84
|
+
block: positionBlock,
|
|
85
|
+
isEditor: false,
|
|
86
|
+
selection: {
|
|
87
|
+
anchor: utils.getBlockStartPoint({
|
|
88
|
+
node: block,
|
|
89
|
+
path: [{_key: block._key}],
|
|
90
|
+
}),
|
|
91
|
+
focus: utils.getBlockEndPoint({
|
|
92
|
+
node: block,
|
|
93
|
+
path: [{_key: block._key}],
|
|
94
|
+
}),
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
68
99
|
return {
|
|
69
100
|
block: positionBlock,
|
|
70
101
|
isEditor: Editor.isEditor(node),
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {Editor, Node, type Path} from 'slate'
|
|
1
|
+
import {Editor, Element, Node, type Path} from 'slate'
|
|
2
|
+
import type {EditorSchema} from '../editor/define-schema'
|
|
2
3
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
4
|
+
import {fromSlateValue} from './values'
|
|
3
5
|
|
|
4
6
|
export function getFocusBlock({
|
|
5
7
|
editor,
|
|
@@ -54,3 +56,60 @@ export function getLastBlock({
|
|
|
54
56
|
|
|
55
57
|
return lastBlock ?? [undefined, undefined]
|
|
56
58
|
}
|
|
59
|
+
|
|
60
|
+
export function getNodeBlock({
|
|
61
|
+
editor,
|
|
62
|
+
schema,
|
|
63
|
+
node,
|
|
64
|
+
}: {
|
|
65
|
+
editor: PortableTextSlateEditor
|
|
66
|
+
schema: EditorSchema
|
|
67
|
+
node: Node
|
|
68
|
+
}) {
|
|
69
|
+
if (Editor.isEditor(node)) {
|
|
70
|
+
return undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (isBlockElement(schema, node)) {
|
|
74
|
+
return elementToBlock({schema, element: node})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const parent = Array.from(
|
|
78
|
+
Editor.nodes(editor, {
|
|
79
|
+
mode: 'highest',
|
|
80
|
+
at: [],
|
|
81
|
+
match: (n) =>
|
|
82
|
+
isBlockElement(schema, n) &&
|
|
83
|
+
n.children.some((child) => child._key === node._key),
|
|
84
|
+
}),
|
|
85
|
+
)
|
|
86
|
+
.at(0)
|
|
87
|
+
?.at(0)
|
|
88
|
+
|
|
89
|
+
return Element.isElement(parent)
|
|
90
|
+
? elementToBlock({
|
|
91
|
+
schema,
|
|
92
|
+
element: parent,
|
|
93
|
+
})
|
|
94
|
+
: undefined
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function elementToBlock({
|
|
98
|
+
schema,
|
|
99
|
+
element,
|
|
100
|
+
}: {
|
|
101
|
+
schema: EditorSchema
|
|
102
|
+
element: Element
|
|
103
|
+
}) {
|
|
104
|
+
return fromSlateValue([element], schema.block.name)?.at(0)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isBlockElement(schema: EditorSchema, node: Node): node is Element {
|
|
108
|
+
return (
|
|
109
|
+
Element.isElement(node) &&
|
|
110
|
+
(schema.block.name === node._type ||
|
|
111
|
+
schema.blockObjects.some(
|
|
112
|
+
(blockObject) => blockObject.name === node._type,
|
|
113
|
+
))
|
|
114
|
+
)
|
|
115
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {KeyedSegment
|
|
1
|
+
import type {KeyedSegment} from '@sanity/types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
5
5
|
*/
|
|
6
|
-
export function isKeyedSegment(segment:
|
|
6
|
+
export function isKeyedSegment(segment: unknown): segment is KeyedSegment {
|
|
7
7
|
return typeof segment === 'object' && segment !== null && '_key' in segment
|
|
8
8
|
}
|