@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "1.52.5",
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.4",
98
- "@types/react-dom": "^19.1.5",
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.4.1",
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.5"
114
+ "racejar": "1.2.6"
116
115
  },
117
116
  "peerDependencies": {
118
117
  "@sanity/schema": "^3.92.0",
@@ -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
- isPortableTextSpan,
3
- type Path,
4
- type PortableTextBlock,
5
- type PortableTextChild,
6
- type PortableTextObject,
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
- return isAnnotationActive({editor, annotation: {name: annotationType}})
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
- pluginUpdateSelection({
70
- editorActor,
71
- editor: pluginUpdateValue(
69
+ pluginUpdateValue(
70
+ editorActor.getSnapshot().context,
71
+ pluginUpdateMarkState(
72
72
  editorActor.getSnapshot().context,
73
- pluginUpdateMarkState(
74
- editorActor.getSnapshot().context,
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, getSelectedSpans} from './slate-utils'
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 selectedSpans = getSelectedSpans({editor})
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 [span] of selectedSpans) {
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
  }: {