@portabletext/editor 1.52.5 → 1.52.7
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/index.cjs +28 -53
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +30 -55
- package/lib/index.js.map +1 -1
- package/package.json +5 -6
- package/src/editor/Editable.tsx +14 -3
- package/src/editor/plugins/createWithEditableAPI.ts +13 -64
- package/src/editor/plugins/with-plugins.ts +8 -8
- package/src/internal-utils/mark-state.ts +28 -6
- package/src/internal-utils/slate-utils.ts +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.52.
|
|
3
|
+
"version": "1.52.7",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -89,16 +89,15 @@
|
|
|
89
89
|
"@sanity/pkg-utils": "^7.2.4",
|
|
90
90
|
"@sanity/schema": "^3.92.0",
|
|
91
91
|
"@sanity/types": "^3.92.0",
|
|
92
|
-
"@testing-library/jest-dom": "^6.6.3",
|
|
93
92
|
"@testing-library/react": "^16.3.0",
|
|
94
93
|
"@types/debug": "^4.1.12",
|
|
95
94
|
"@types/lodash": "^4.17.16",
|
|
96
95
|
"@types/lodash.startcase": "^4.4.9",
|
|
97
|
-
"@types/react": "^19.1.
|
|
98
|
-
"@types/react-dom": "^19.1.
|
|
96
|
+
"@types/react": "^19.1.8",
|
|
97
|
+
"@types/react-dom": "^19.1.6",
|
|
99
98
|
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
|
100
99
|
"@typescript-eslint/parser": "^8.33.0",
|
|
101
|
-
"@vitejs/plugin-react": "^4.
|
|
100
|
+
"@vitejs/plugin-react": "^4.5.2",
|
|
102
101
|
"@vitest/browser": "^3.2.3",
|
|
103
102
|
"@vitest/coverage-istanbul": "^3.2.3",
|
|
104
103
|
"babel-plugin-react-compiler": "19.1.0-rc.1",
|
|
@@ -112,7 +111,7 @@
|
|
|
112
111
|
"vite": "^6.2.5",
|
|
113
112
|
"vitest": "^3.2.3",
|
|
114
113
|
"vitest-browser-react": "^0.2.0",
|
|
115
|
-
"racejar": "1.2.
|
|
114
|
+
"racejar": "1.2.6"
|
|
116
115
|
},
|
|
117
116
|
"peerDependencies": {
|
|
118
117
|
"@sanity/schema": "^3.92.0",
|
package/src/editor/Editable.tsx
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type MutableRefObject,
|
|
16
16
|
type TextareaHTMLAttributes,
|
|
17
17
|
} from 'react'
|
|
18
|
-
import {Transforms, type Text} from 'slate'
|
|
18
|
+
import {Editor, Transforms, type Text} from 'slate'
|
|
19
19
|
import {
|
|
20
20
|
ReactEditor,
|
|
21
21
|
Editable as SlateEditable,
|
|
@@ -29,7 +29,7 @@ import {parseBlocks} from '../internal-utils/parse-blocks'
|
|
|
29
29
|
import {toSlateRange} from '../internal-utils/ranges'
|
|
30
30
|
import {normalizeSelection} from '../internal-utils/selection'
|
|
31
31
|
import {slateRangeToSelection} from '../internal-utils/slate-utils'
|
|
32
|
-
import {fromSlateValue} from '../internal-utils/values'
|
|
32
|
+
import {fromSlateValue, isEqualToEmptyEditor} from '../internal-utils/values'
|
|
33
33
|
import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
|
|
34
34
|
import type {
|
|
35
35
|
EditorSelection,
|
|
@@ -534,9 +534,20 @@ export const PortableTextEditable = forwardRef<
|
|
|
534
534
|
|
|
535
535
|
if (!event.isDefaultPrevented()) {
|
|
536
536
|
relayActor.send({type: 'focused', event})
|
|
537
|
+
|
|
538
|
+
if (
|
|
539
|
+
!slateEditor.selection &&
|
|
540
|
+
isEqualToEmptyEditor(
|
|
541
|
+
slateEditor.children,
|
|
542
|
+
editorActor.getSnapshot().context.schema,
|
|
543
|
+
)
|
|
544
|
+
) {
|
|
545
|
+
Transforms.select(slateEditor, Editor.start(slateEditor, []))
|
|
546
|
+
slateEditor.onChange()
|
|
547
|
+
}
|
|
537
548
|
}
|
|
538
549
|
},
|
|
539
|
-
[onFocus, relayActor],
|
|
550
|
+
[editorActor, onFocus, relayActor, slateEditor],
|
|
540
551
|
)
|
|
541
552
|
|
|
542
553
|
const handleClick = useCallback(
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
type PortableTextTextBlock,
|
|
1
|
+
import type {
|
|
2
|
+
Path,
|
|
3
|
+
PortableTextBlock,
|
|
4
|
+
PortableTextChild,
|
|
5
|
+
PortableTextObject,
|
|
6
|
+
PortableTextTextBlock,
|
|
8
7
|
} from '@sanity/types'
|
|
9
8
|
import {
|
|
10
9
|
Editor,
|
|
@@ -29,6 +28,7 @@ import {
|
|
|
29
28
|
SLATE_TO_PORTABLE_TEXT_RANGE,
|
|
30
29
|
} from '../../internal-utils/weakMaps'
|
|
31
30
|
import {addAnnotationOperationImplementation} from '../../operations/behavior.operation.annotation.add'
|
|
31
|
+
import {isActiveAnnotation} from '../../selectors'
|
|
32
32
|
import type {
|
|
33
33
|
EditableAPI,
|
|
34
34
|
EditableAPIDeleteOptions,
|
|
@@ -396,7 +396,12 @@ export function createEditableAPI(
|
|
|
396
396
|
isAnnotationActive: (
|
|
397
397
|
annotationType: PortableTextObject['_type'],
|
|
398
398
|
): boolean => {
|
|
399
|
-
|
|
399
|
+
const snapshot = getEditorSnapshot({
|
|
400
|
+
editorActorSnapshot: editorActor.getSnapshot(),
|
|
401
|
+
slateEditorInstance: editor,
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
return isActiveAnnotation(annotationType)(snapshot)
|
|
400
405
|
},
|
|
401
406
|
addAnnotation: (type, value) => {
|
|
402
407
|
let paths: ReturnType<EditableAPI['addAnnotation']> = undefined
|
|
@@ -546,59 +551,3 @@ export function createEditableAPI(
|
|
|
546
551
|
|
|
547
552
|
return editableApi
|
|
548
553
|
}
|
|
549
|
-
|
|
550
|
-
function isAnnotationActive({
|
|
551
|
-
editor,
|
|
552
|
-
annotation,
|
|
553
|
-
}: {
|
|
554
|
-
editor: PortableTextSlateEditor
|
|
555
|
-
annotation: {
|
|
556
|
-
name: string
|
|
557
|
-
}
|
|
558
|
-
}) {
|
|
559
|
-
if (!editor.selection || editor.selection.focus.path.length < 2) {
|
|
560
|
-
return false
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
try {
|
|
564
|
-
const spans = [
|
|
565
|
-
...Editor.nodes(editor, {
|
|
566
|
-
at: editor.selection,
|
|
567
|
-
match: (node) => Text.isText(node),
|
|
568
|
-
}),
|
|
569
|
-
]
|
|
570
|
-
|
|
571
|
-
if (spans.length === 0) {
|
|
572
|
-
return false
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
if (
|
|
576
|
-
spans.some(
|
|
577
|
-
([span]) =>
|
|
578
|
-
!isPortableTextSpan(span) || !span.marks || span.marks?.length === 0,
|
|
579
|
-
)
|
|
580
|
-
)
|
|
581
|
-
return false
|
|
582
|
-
|
|
583
|
-
const selectionMarkDefs = spans.reduce((accMarkDefs, [, path]) => {
|
|
584
|
-
const [block] = Editor.node(editor, path, {depth: 1})
|
|
585
|
-
if (editor.isTextBlock(block) && block.markDefs) {
|
|
586
|
-
return [...accMarkDefs, ...block.markDefs]
|
|
587
|
-
}
|
|
588
|
-
return accMarkDefs
|
|
589
|
-
}, [] as PortableTextObject[])
|
|
590
|
-
|
|
591
|
-
return spans.every(([span]) => {
|
|
592
|
-
if (!isPortableTextSpan(span)) return false
|
|
593
|
-
|
|
594
|
-
const spanMarkDefs = span.marks?.map(
|
|
595
|
-
(markKey) =>
|
|
596
|
-
selectionMarkDefs.find((def) => def?._key === markKey)?._type,
|
|
597
|
-
)
|
|
598
|
-
|
|
599
|
-
return spanMarkDefs?.includes(annotation.name)
|
|
600
|
-
})
|
|
601
|
-
} catch {
|
|
602
|
-
return false
|
|
603
|
-
}
|
|
604
|
-
}
|
|
@@ -66,16 +66,16 @@ export const withPlugins = <T extends Editor>(
|
|
|
66
66
|
withMaxBlocks(
|
|
67
67
|
withUndoRedo(
|
|
68
68
|
withPatches(
|
|
69
|
-
|
|
70
|
-
editorActor,
|
|
71
|
-
|
|
69
|
+
pluginUpdateValue(
|
|
70
|
+
editorActor.getSnapshot().context,
|
|
71
|
+
pluginUpdateMarkState(
|
|
72
72
|
editorActor.getSnapshot().context,
|
|
73
|
-
|
|
74
|
-
editorActor
|
|
75
|
-
e,
|
|
76
|
-
),
|
|
73
|
+
pluginUpdateSelection({
|
|
74
|
+
editorActor,
|
|
75
|
+
editor: e,
|
|
76
|
+
}),
|
|
77
77
|
),
|
|
78
|
-
|
|
78
|
+
),
|
|
79
79
|
),
|
|
80
80
|
),
|
|
81
81
|
),
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {Range} from 'slate'
|
|
2
2
|
import type {EditorSchema} from '../editor/editor-schema'
|
|
3
|
+
import {getSelectedSpans} from '../selectors'
|
|
3
4
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
4
5
|
import {getNextSpan, getPreviousSpan} from './sibling-utils'
|
|
5
|
-
import {getFocusBlock, getFocusSpan,
|
|
6
|
+
import {getFocusBlock, getFocusSpan, slateRangeToSelection} from './slate-utils'
|
|
6
7
|
|
|
7
8
|
export type MarkState = {
|
|
8
9
|
state: 'changed' | 'unchanged'
|
|
@@ -36,18 +37,39 @@ export function getMarkState({
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
if (Range.isExpanded(editor.selection)) {
|
|
39
|
-
const
|
|
40
|
+
const selection = editor.selection
|
|
41
|
+
? slateRangeToSelection({
|
|
42
|
+
schema,
|
|
43
|
+
editor,
|
|
44
|
+
range: editor.selection,
|
|
45
|
+
})
|
|
46
|
+
: null
|
|
47
|
+
|
|
48
|
+
const selectedSpans = getSelectedSpans({
|
|
49
|
+
context: {
|
|
50
|
+
value: editor.value,
|
|
51
|
+
selection,
|
|
52
|
+
schema,
|
|
53
|
+
converters: [],
|
|
54
|
+
keyGenerator: () => '',
|
|
55
|
+
readOnly: false,
|
|
56
|
+
},
|
|
57
|
+
beta: {
|
|
58
|
+
activeAnnotations: [],
|
|
59
|
+
activeDecorators: [],
|
|
60
|
+
},
|
|
61
|
+
})
|
|
40
62
|
|
|
41
63
|
let index = 0
|
|
42
64
|
let marks: Array<string> = []
|
|
43
65
|
|
|
44
|
-
for (const
|
|
66
|
+
for (const span of selectedSpans) {
|
|
45
67
|
if (index === 0) {
|
|
46
|
-
marks = span.marks ?? []
|
|
68
|
+
marks = span.node.marks ?? []
|
|
47
69
|
} else {
|
|
48
70
|
if (
|
|
49
|
-
span.marks?.length === 0 ||
|
|
50
|
-
(span.marks ?? [])?.some((mark) => !marks.includes(mark))
|
|
71
|
+
span.node.marks?.length === 0 ||
|
|
72
|
+
(span.node.marks ?? [])?.some((mark) => !marks.includes(mark))
|
|
51
73
|
) {
|
|
52
74
|
marks = []
|
|
53
75
|
}
|
|
@@ -91,27 +91,6 @@ export function getFocusSpan({
|
|
|
91
91
|
return [undefined, undefined]
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function getSelectedSpans({
|
|
95
|
-
editor,
|
|
96
|
-
}: {
|
|
97
|
-
editor: PortableTextSlateEditor
|
|
98
|
-
}): Array<[node: PortableTextSpan, path: Path]> {
|
|
99
|
-
if (!editor.selection) {
|
|
100
|
-
return []
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
return Array.from(
|
|
105
|
-
Editor.nodes(editor, {
|
|
106
|
-
at: editor.selection,
|
|
107
|
-
match: (node) => editor.isTextSpan(node),
|
|
108
|
-
}),
|
|
109
|
-
)
|
|
110
|
-
} catch {
|
|
111
|
-
return []
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
94
|
export function getSelectionStartBlock({
|
|
116
95
|
editor,
|
|
117
96
|
}: {
|