@portabletext/editor 1.24.0 → 1.26.0
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 +283 -64
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.get-text-before.cjs +8 -8
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs +412 -0
- package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs.map +1 -0
- package/lib/_chunks-cjs/util.is-empty-text-block.cjs +2 -2
- package/lib/_chunks-cjs/util.is-empty-text-block.cjs.map +1 -1
- package/lib/_chunks-cjs/util.is-equal-selection-points.cjs +46 -0
- package/lib/_chunks-cjs/util.is-equal-selection-points.cjs.map +1 -0
- package/lib/_chunks-cjs/util.reverse-selection.cjs +0 -16
- package/lib/_chunks-cjs/util.reverse-selection.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +259 -40
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/selector.get-text-before.js +2 -2
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js +414 -0
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -0
- package/lib/_chunks-es/util.is-empty-text-block.js +1 -1
- package/lib/_chunks-es/util.is-equal-selection-points.js +47 -0
- package/lib/_chunks-es/util.is-equal-selection-points.js.map +1 -0
- package/lib/_chunks-es/util.reverse-selection.js +0 -16
- package/lib/_chunks-es/util.reverse-selection.js.map +1 -1
- package/lib/behaviors/index.cjs +27 -27
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +2208 -171
- package/lib/behaviors/index.d.ts +2208 -171
- package/lib/behaviors/index.js +1 -1
- package/lib/index.cjs +306 -298
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +10499 -521
- package/lib/index.d.ts +10499 -521
- package/lib/index.js +302 -294
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +26 -171
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +16 -0
- package/lib/selectors/index.d.ts +16 -0
- package/lib/selectors/index.js +5 -151
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.cjs +5 -3
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.cts +19 -0
- package/lib/utils/index.d.ts +19 -0
- package/lib/utils/index.js +4 -2
- package/package.json +6 -6
- package/src/behavior-actions/behavior.action-utils.insert-block.ts +3 -3
- package/src/behavior-actions/behavior.action.block.set.ts +23 -0
- package/src/behavior-actions/behavior.action.block.unset.ts +21 -0
- package/src/behavior-actions/behavior.action.insert-break.ts +2 -69
- package/src/behavior-actions/behavior.action.insert.block.ts +29 -0
- package/src/behavior-actions/behavior.actions.ts +116 -96
- package/src/behaviors/behavior.core.annotations.ts +29 -0
- package/src/behaviors/behavior.core.block-objects.ts +13 -13
- package/src/behaviors/behavior.core.decorators.ts +19 -0
- package/src/behaviors/behavior.core.insert-break.ts +122 -0
- package/src/behaviors/behavior.core.lists.ts +57 -23
- package/src/behaviors/behavior.core.style.ts +19 -0
- package/src/behaviors/behavior.core.ts +18 -2
- package/src/behaviors/behavior.types.ts +103 -88
- package/src/converters/converter.json.ts +4 -4
- package/src/converters/converter.portable-text.deserialize.test.ts +1 -1
- package/src/converters/converter.portable-text.ts +4 -4
- package/src/converters/converter.text-html.deserialize.test.ts +1 -1
- package/src/converters/converter.text-html.serialize.test.ts +1 -1
- package/src/converters/converter.text-html.ts +4 -4
- package/src/converters/converter.text-plain.test.ts +1 -1
- package/src/converters/converter.text-plain.ts +3 -3
- package/src/converters/{converter.ts → converter.types.ts} +6 -0
- package/src/editor/create-editor.ts +50 -7
- package/src/editor/editor-machine.ts +46 -3
- package/src/editor/editor-snapshot.ts +1 -1
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +2 -2
- package/src/editor/plugins/create-with-event-listeners.ts +41 -106
- package/src/selectors/index.ts +2 -0
- package/src/selectors/selector.is-at-the-end-of-block.ts +22 -0
- package/src/selectors/selector.is-at-the-start-of-block.ts +25 -0
- package/src/selectors/selector.is-selection-collapsed.ts +6 -2
- package/src/utils/index.ts +2 -0
- package/src/utils/util.get-block-end-point.ts +34 -0
- package/src/utils/util.is-equal-selection-points.ts +13 -0
- package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs +0 -231
- package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs.map +0 -1
- package/lib/_chunks-cjs/util.is-keyed-segment.cjs +0 -6
- package/lib/_chunks-cjs/util.is-keyed-segment.cjs.map +0 -1
- package/lib/_chunks-es/selector.is-selection-collapsed.js +0 -232
- package/lib/_chunks-es/selector.is-selection-collapsed.js.map +0 -1
- package/lib/_chunks-es/util.is-keyed-segment.js +0 -7
- package/lib/_chunks-es/util.is-keyed-segment.js.map +0 -1
- /package/src/converters/{converters.ts → converters.core.ts} +0 -0
package/lib/utils/index.d.ts
CHANGED
|
@@ -38,6 +38,17 @@ export declare type EditorSelectionPoint = {
|
|
|
38
38
|
offset: number
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export declare function getBlockEndPoint({
|
|
45
|
+
node,
|
|
46
|
+
path,
|
|
47
|
+
}: {
|
|
48
|
+
node: PortableTextBlock
|
|
49
|
+
path: [KeyedSegment]
|
|
50
|
+
}): EditorSelectionPoint
|
|
51
|
+
|
|
41
52
|
/**
|
|
42
53
|
* @public
|
|
43
54
|
*/
|
|
@@ -59,6 +70,14 @@ export declare function getTextBlockText(block: PortableTextTextBlock): string
|
|
|
59
70
|
*/
|
|
60
71
|
export declare function isEmptyTextBlock(block: PortableTextBlock): boolean
|
|
61
72
|
|
|
73
|
+
/**
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
export declare function isEqualSelectionPoints(
|
|
77
|
+
a: EditorSelectionPoint,
|
|
78
|
+
b: EditorSelectionPoint,
|
|
79
|
+
): boolean
|
|
80
|
+
|
|
62
81
|
/**
|
|
63
82
|
* @public
|
|
64
83
|
*/
|
package/lib/utils/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { blockOffsetToSpanSelectionPoint, getTextBlockText, isEmptyTextBlock, spanSelectionPointToBlockOffset } from "../_chunks-es/util.is-empty-text-block.js";
|
|
2
|
-
import { getBlockStartPoint,
|
|
3
|
-
import {
|
|
2
|
+
import { getBlockEndPoint, getBlockStartPoint, isEqualSelectionPoints, isKeyedSegment } from "../_chunks-es/util.is-equal-selection-points.js";
|
|
3
|
+
import { reverseSelection } from "../_chunks-es/util.reverse-selection.js";
|
|
4
4
|
import { sliceBlocks } from "../_chunks-es/util.slice-blocks.js";
|
|
5
5
|
export {
|
|
6
6
|
blockOffsetToSpanSelectionPoint,
|
|
7
|
+
getBlockEndPoint,
|
|
7
8
|
getBlockStartPoint,
|
|
8
9
|
getTextBlockText,
|
|
9
10
|
isEmptyTextBlock,
|
|
11
|
+
isEqualSelectionPoints,
|
|
10
12
|
isKeyedSegment,
|
|
11
13
|
reverseSelection,
|
|
12
14
|
sliceBlocks,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -73,15 +73,15 @@
|
|
|
73
73
|
"slate-react": "0.112.1",
|
|
74
74
|
"use-effect-event": "^1.0.2",
|
|
75
75
|
"xstate": "^5.19.2",
|
|
76
|
-
"@portabletext/block-tools": "1.1.
|
|
76
|
+
"@portabletext/block-tools": "1.1.2",
|
|
77
77
|
"@portabletext/patches": "1.1.2"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@portabletext/toolkit": "^2.0.16",
|
|
81
81
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
82
82
|
"@sanity/pkg-utils": "^7.0.2",
|
|
83
|
-
"@sanity/schema": "^3.71.
|
|
84
|
-
"@sanity/types": "^3.71.
|
|
83
|
+
"@sanity/schema": "^3.71.1",
|
|
84
|
+
"@sanity/types": "^3.71.1",
|
|
85
85
|
"@testing-library/jest-dom": "^6.6.3",
|
|
86
86
|
"@testing-library/react": "^16.2.0",
|
|
87
87
|
"@types/debug": "^4.1.12",
|
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
"racejar": "1.1.1"
|
|
110
110
|
},
|
|
111
111
|
"peerDependencies": {
|
|
112
|
-
"@sanity/schema": "^3.71.
|
|
113
|
-
"@sanity/types": "^3.71.
|
|
112
|
+
"@sanity/schema": "^3.71.1",
|
|
113
|
+
"@sanity/types": "^3.71.1",
|
|
114
114
|
"react": "^16.9 || ^17 || ^18 || ^19",
|
|
115
115
|
"rxjs": "^7.8.1"
|
|
116
116
|
},
|
|
@@ -52,10 +52,10 @@ export function insertBlock({
|
|
|
52
52
|
Transforms.insertNodes(editor, block, {at: focusBlockPath})
|
|
53
53
|
} else {
|
|
54
54
|
Editor.insertNode(editor, block)
|
|
55
|
-
}
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
if (focusBlock && isEqualToEmptyEditor([focusBlock], schema)) {
|
|
57
|
+
Transforms.removeNodes(editor, {at: focusBlockPath})
|
|
58
|
+
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {Transforms} from 'slate'
|
|
2
|
+
import {toSlateRange} from '../internal-utils/ranges'
|
|
3
|
+
import type {BehaviorActionImplementation} from './behavior.actions'
|
|
4
|
+
|
|
5
|
+
export const blockSetBehaviorActionImplementation: BehaviorActionImplementation<
|
|
6
|
+
'block.set'
|
|
7
|
+
> = ({action}) => {
|
|
8
|
+
const location = toSlateRange(
|
|
9
|
+
{
|
|
10
|
+
anchor: {path: action.at, offset: 0},
|
|
11
|
+
focus: {path: action.at, offset: 0},
|
|
12
|
+
},
|
|
13
|
+
action.editor,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if (!location) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const {at, editor, type, ...payload} = action
|
|
21
|
+
|
|
22
|
+
Transforms.setNodes(action.editor, payload, {at: location})
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {Transforms} from 'slate'
|
|
2
|
+
import {toSlateRange} from '../internal-utils/ranges'
|
|
3
|
+
import type {BehaviorActionImplementation} from './behavior.actions'
|
|
4
|
+
|
|
5
|
+
export const blockUnsetBehaviorActionImplementation: BehaviorActionImplementation<
|
|
6
|
+
'block.unset'
|
|
7
|
+
> = ({action}) => {
|
|
8
|
+
const location = toSlateRange(
|
|
9
|
+
{
|
|
10
|
+
anchor: {path: action.at, offset: 0},
|
|
11
|
+
focus: {path: action.at, offset: 0},
|
|
12
|
+
},
|
|
13
|
+
action.editor,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if (!location) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
Transforms.unsetNodes(action.editor, action.props, {at: location})
|
|
21
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {isEqual} from 'lodash'
|
|
2
|
-
import {Editor, Node, Path,
|
|
2
|
+
import {Editor, Node, Path, Transforms} from 'slate'
|
|
3
3
|
import type {SlateTextBlock, VoidElement} from '../types/slate'
|
|
4
4
|
import type {BehaviorActionImplementation} from './behavior.actions'
|
|
5
5
|
|
|
@@ -14,24 +14,6 @@ export const insertBreakActionImplementation: BehaviorActionImplementation<
|
|
|
14
14
|
return
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const [focusSpan] = Array.from(
|
|
18
|
-
Editor.nodes(editor, {
|
|
19
|
-
mode: 'lowest',
|
|
20
|
-
at: editor.selection.focus,
|
|
21
|
-
match: (n) => editor.isTextSpan(n),
|
|
22
|
-
voids: false,
|
|
23
|
-
}),
|
|
24
|
-
)[0] ?? [undefined]
|
|
25
|
-
const focusDecorators =
|
|
26
|
-
focusSpan?.marks?.filter((mark) =>
|
|
27
|
-
schema.decorators.some((decorator) => decorator.value === mark),
|
|
28
|
-
) ?? []
|
|
29
|
-
const focusAnnotations =
|
|
30
|
-
focusSpan?.marks?.filter(
|
|
31
|
-
(mark) =>
|
|
32
|
-
!schema.decorators.some((decorator) => decorator.value === mark),
|
|
33
|
-
) ?? []
|
|
34
|
-
|
|
35
17
|
const anchorBlockPath = editor.selection.anchor.path.slice(0, 1)
|
|
36
18
|
const focusBlockPath = editor.selection.focus.path.slice(0, 1)
|
|
37
19
|
const focusBlock = Node.descendant(editor, focusBlockPath) as
|
|
@@ -39,58 +21,9 @@ export const insertBreakActionImplementation: BehaviorActionImplementation<
|
|
|
39
21
|
| VoidElement
|
|
40
22
|
|
|
41
23
|
if (editor.isTextBlock(focusBlock)) {
|
|
42
|
-
const [start, end] = Range.edges(editor.selection)
|
|
43
|
-
const lastFocusBlockChild =
|
|
44
|
-
focusBlock.children[focusBlock.children.length - 1]
|
|
45
|
-
const atTheEndOfBlock = isEqual(start, {
|
|
46
|
-
path: [...focusBlockPath, focusBlock.children.length - 1],
|
|
47
|
-
offset: editor.isTextSpan(lastFocusBlockChild)
|
|
48
|
-
? lastFocusBlockChild.text.length
|
|
49
|
-
: 0,
|
|
50
|
-
})
|
|
51
|
-
const atTheStartOfBlock = isEqual(end, {
|
|
52
|
-
path: [...focusBlockPath, 0],
|
|
53
|
-
offset: 0,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
if (atTheEndOfBlock && Range.isCollapsed(editor.selection)) {
|
|
57
|
-
Editor.insertNode(
|
|
58
|
-
editor,
|
|
59
|
-
editor.pteCreateTextBlock({
|
|
60
|
-
decorators: [],
|
|
61
|
-
listItem: focusBlock.listItem,
|
|
62
|
-
level: focusBlock.level,
|
|
63
|
-
}),
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (atTheStartOfBlock && Range.isCollapsed(editor.selection)) {
|
|
70
|
-
Editor.insertNode(
|
|
71
|
-
editor,
|
|
72
|
-
editor.pteCreateTextBlock({
|
|
73
|
-
decorators: focusAnnotations.length === 0 ? focusDecorators : [],
|
|
74
|
-
listItem: focusBlock.listItem,
|
|
75
|
-
level: focusBlock.level,
|
|
76
|
-
}),
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
const [nextBlockPath] = Path.next(focusBlockPath)
|
|
80
|
-
|
|
81
|
-
Transforms.select(editor, {
|
|
82
|
-
anchor: {path: [nextBlockPath, 0], offset: 0},
|
|
83
|
-
focus: {path: [nextBlockPath, 0], offset: 0},
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
24
|
const selectionAcrossBlocks = anchorBlockPath[0] !== focusBlockPath[0]
|
|
90
25
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (isInTheMiddleOfNode && !selectionAcrossBlocks) {
|
|
26
|
+
if (!selectionAcrossBlocks) {
|
|
94
27
|
Editor.withoutNormalizing(editor, () => {
|
|
95
28
|
if (!editor.selection) {
|
|
96
29
|
return
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {parseBlock} from '../internal-utils/parse-blocks'
|
|
2
|
+
import {toSlateValue} from '../internal-utils/values'
|
|
3
|
+
import {insertBlock} from './behavior.action-utils.insert-block'
|
|
4
|
+
import type {BehaviorActionImplementation} from './behavior.actions'
|
|
5
|
+
|
|
6
|
+
export const insertBlockActionImplementation: BehaviorActionImplementation<
|
|
7
|
+
'insert.block'
|
|
8
|
+
> = ({context, action}) => {
|
|
9
|
+
const parsedBlock = parseBlock({block: action.block, context})
|
|
10
|
+
|
|
11
|
+
if (!parsedBlock) {
|
|
12
|
+
throw new Error(`Failed to parse block ${JSON.stringify(action.block)}`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const fragment = toSlateValue([parsedBlock], {schemaTypes: context.schema})[0]
|
|
16
|
+
|
|
17
|
+
if (!fragment) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Failed to convert block to Slate fragment ${JSON.stringify(parsedBlock)}`,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
insertBlock({
|
|
24
|
+
block: fragment,
|
|
25
|
+
placement: action.placement,
|
|
26
|
+
editor: action.editor,
|
|
27
|
+
schema: context.schema,
|
|
28
|
+
})
|
|
29
|
+
}
|