@portabletext/editor 2.8.1 → 2.8.3

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.
@@ -1,5 +1,5 @@
1
1
  import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.cjs";
2
- import * as react11 from "react";
2
+ import * as react12 from "react";
3
3
  import React from "react";
4
4
  /**
5
5
  * @beta
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
181
181
  */
182
182
  declare function MarkdownPlugin(props: {
183
183
  config: MarkdownPluginConfig;
184
- }): react11.JSX.Element;
184
+ }): react12.JSX.Element;
185
185
  /**
186
186
  * @beta
187
187
  * Restrict the editor to one line. The plugin takes care of blocking
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
192
192
  *
193
193
  * @deprecated Install the plugin from `@portabletext/plugin-one-line`
194
194
  */
195
- declare function OneLinePlugin(): react11.JSX.Element;
195
+ declare function OneLinePlugin(): react12.JSX.Element;
196
196
  export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
@@ -1,5 +1,5 @@
1
1
  import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.js";
2
- import * as react12 from "react";
2
+ import * as react22 from "react";
3
3
  import React from "react";
4
4
  /**
5
5
  * @beta
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
181
181
  */
182
182
  declare function MarkdownPlugin(props: {
183
183
  config: MarkdownPluginConfig;
184
- }): react12.JSX.Element;
184
+ }): react22.JSX.Element;
185
185
  /**
186
186
  * @beta
187
187
  * Restrict the editor to one line. The plugin takes care of blocking
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
192
192
  *
193
193
  * @deprecated Install the plugin from `@portabletext/plugin-one-line`
194
194
  */
195
- declare function OneLinePlugin(): react12.JSX.Element;
195
+ declare function OneLinePlugin(): react22.JSX.Element;
196
196
  export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "2.8.1",
3
+ "version": "2.8.3",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -79,7 +79,7 @@
79
79
  "slate-dom": "^0.118.1",
80
80
  "slate-react": "0.117.4",
81
81
  "xstate": "^5.21.0",
82
- "@portabletext/block-tools": "^3.5.3",
82
+ "@portabletext/block-tools": "^3.5.4",
83
83
  "@portabletext/keyboard-shortcuts": "^1.1.1",
84
84
  "@portabletext/patches": "^1.1.8",
85
85
  "@portabletext/schema": "^1.2.0"
@@ -16,8 +16,8 @@ import {Subject} from 'rxjs'
16
16
  import {Slate} from 'slate-react'
17
17
  import {debugWithName} from '../internal-utils/debug'
18
18
  import {stopActor} from '../internal-utils/stop-actor'
19
- import type {AddedAnnotationPaths} from '../operations/behavior.operation.annotation.add'
20
19
  import type {
20
+ AddedAnnotationPaths,
21
21
  EditableAPI,
22
22
  EditableAPIDeleteOptions,
23
23
  EditorChange,
@@ -1,3 +1,4 @@
1
+ import {isTextBlock} from '@portabletext/schema'
1
2
  import type {
2
3
  Path,
3
4
  PortableTextBlock,
@@ -29,8 +30,12 @@ import {
29
30
  KEY_TO_VALUE_ELEMENT,
30
31
  SLATE_TO_PORTABLE_TEXT_RANGE,
31
32
  } from '../../internal-utils/weakMaps'
32
- import {addAnnotationOperationImplementation} from '../../operations/behavior.operation.annotation.add'
33
- import {isActiveAnnotation} from '../../selectors'
33
+ import {
34
+ getFocusBlock,
35
+ getFocusSpan,
36
+ getSelectedValue,
37
+ isActiveAnnotation,
38
+ } from '../../selectors'
34
39
  import {getActiveAnnotationsMarks} from '../../selectors/selector.get-active-annotation-marks'
35
40
  import {getActiveDecorators} from '../../selectors/selector.get-active-decorators'
36
41
  import type {
@@ -424,40 +429,77 @@ export function createEditableAPI(
424
429
  return isActiveAnnotation(annotationType)(snapshot)
425
430
  },
426
431
  addAnnotation: (type, value) => {
427
- let paths: ReturnType<EditableAPI['addAnnotation']>
432
+ const snapshotBefore = getEditorSnapshot({
433
+ editorActorSnapshot: editorActor.getSnapshot(),
434
+ slateEditorInstance: editor,
435
+ })
436
+ const selectedValueBefore = getSelectedValue(snapshotBefore)
437
+ const focusSpanBefore = getFocusSpan(snapshotBefore)
438
+ const markDefsBefore = selectedValueBefore.flatMap((block) => {
439
+ if (isTextBlock(snapshotBefore.context, block)) {
440
+ return block.markDefs ?? []
441
+ }
428
442
 
429
- const snapshot = getEditorSnapshot({
443
+ return []
444
+ })
445
+
446
+ editorActor.send({
447
+ type: 'behavior event',
448
+ behaviorEvent: {
449
+ type: 'annotation.add',
450
+ annotation: {name: type.name, value: value ?? {}},
451
+ },
452
+ editor,
453
+ })
454
+
455
+ const snapshotAfter = getEditorSnapshot({
430
456
  editorActorSnapshot: editorActor.getSnapshot(),
431
457
  slateEditorInstance: editor,
432
458
  })
433
459
 
434
- if (isActiveAnnotation(type.name, {mode: 'partial'})(snapshot)) {
435
- editorActor.send({
436
- type: 'behavior event',
437
- behaviorEvent: {
438
- type: 'annotation.remove',
439
- annotation: {name: type.name},
440
- },
441
- editor,
442
- })
443
- }
460
+ const selectedValueAfter = getSelectedValue(snapshotAfter)
461
+ const focusBlockAfter = getFocusBlock(snapshotAfter)
462
+ const focusSpanAfter = getFocusSpan(snapshotAfter)
444
463
 
445
- Editor.withoutNormalizing(editor, () => {
446
- paths = addAnnotationOperationImplementation({
447
- context: {
448
- keyGenerator: editorActor.getSnapshot().context.keyGenerator,
449
- schema: types,
450
- },
451
- operation: {
452
- type: 'annotation.add',
453
- annotation: {name: type.name, value: value ?? {}},
454
- editor,
455
- },
456
- })
464
+ const newMarkDefKeysOnFocusSpan = focusSpanAfter?.node.marks?.filter(
465
+ (mark) =>
466
+ !focusSpanBefore?.node.marks?.includes(mark) &&
467
+ !snapshotAfter.context.schema.decorators
468
+ .map((decorator) => decorator.name)
469
+ .includes(mark),
470
+ )
471
+ const markDefsAfter = selectedValueAfter.flatMap((block) => {
472
+ if (isTextBlock(snapshotAfter.context, block)) {
473
+ return (
474
+ block.markDefs?.map((markDef) => ({
475
+ markDef,
476
+ path: [{_key: block._key}, 'markDefs', {_key: markDef._key}],
477
+ })) ?? []
478
+ )
479
+ }
480
+
481
+ return []
457
482
  })
458
- editor.onChange()
483
+ const markDefs = markDefsAfter.filter(
484
+ (markDef) =>
485
+ !markDefsBefore.some(
486
+ (markDefBefore) => markDefBefore._key === markDef.markDef._key,
487
+ ),
488
+ )
489
+ const spanPath = focusSpanAfter?.path
490
+ const markDef = markDefs.find((markDef) =>
491
+ newMarkDefKeysOnFocusSpan?.some(
492
+ (mark) => mark === markDef.markDef._key,
493
+ ),
494
+ )
459
495
 
460
- return paths
496
+ if (focusBlockAfter && spanPath && markDef) {
497
+ return {
498
+ markDefPath: markDef.path,
499
+ markDefPaths: markDefs.map((markDef) => markDef.path),
500
+ spanPath,
501
+ }
502
+ }
461
503
  },
462
504
  delete: (
463
505
  selection: EditorSelection,
package/src/index.ts CHANGED
@@ -45,7 +45,7 @@ export {PortableTextEditor} from './editor/PortableTextEditor'
45
45
  export type {PortableTextEditorProps} from './editor/PortableTextEditor'
46
46
  export type {EditorEmittedEvent, MutationEvent} from './editor/relay-machine'
47
47
  export {useEditor} from './editor/use-editor'
48
- export type {AddedAnnotationPaths} from './operations/behavior.operation.annotation.add'
48
+ export type {AddedAnnotationPaths} from './types/editor'
49
49
  export type {BlockOffset} from './types/block-offset'
50
50
  export type {
51
51
  BlockAnnotationRenderProps,
@@ -1,29 +1,9 @@
1
- import type {Path} from '@sanity/types'
2
1
  import {Editor, Node, Range, Text, Transforms} from 'slate'
3
2
  import {parseAnnotation} from '../internal-utils/parse-blocks'
4
3
  import type {BehaviorOperationImplementation} from './behavior.operations'
5
4
 
6
- /**
7
- * @public
8
- */
9
- export type AddedAnnotationPaths = {
10
- /**
11
- * @deprecated An annotation may be applied to multiple blocks, resulting
12
- * in multiple `markDef`'s being created. Use `markDefPaths` instead.
13
- */
14
- markDefPath: Path
15
- markDefPaths: Array<Path>
16
- /**
17
- * @deprecated Does not return anything meaningful since an annotation
18
- * can span multiple blocks and spans. If references the span closest
19
- * to the focus point of the selection.
20
- */
21
- spanPath: Path
22
- }
23
-
24
5
  export const addAnnotationOperationImplementation: BehaviorOperationImplementation<
25
- 'annotation.add',
26
- AddedAnnotationPaths | undefined
6
+ 'annotation.add'
27
7
  > = ({context, operation}) => {
28
8
  const parsedAnnotation = parseAnnotation({
29
9
  annotation: {
@@ -46,11 +26,6 @@ export const addAnnotationOperationImplementation: BehaviorOperationImplementati
46
26
  return
47
27
  }
48
28
 
49
- let paths: AddedAnnotationPaths | undefined
50
- let spanPath: Path | undefined
51
- let markDefPath: Path | undefined
52
- const markDefPaths: Path[] = []
53
-
54
29
  const selectedBlocks = Editor.nodes(editor, {
55
30
  at: editor.selection,
56
31
  match: (node) => editor.isTextBlock(node),
@@ -92,14 +67,6 @@ export const addAnnotationOperationImplementation: BehaviorOperationImplementati
92
67
  },
93
68
  {at: blockPath},
94
69
  )
95
-
96
- markDefPath = [{_key: block._key}, 'markDefs', {_key: annotationKey}]
97
-
98
- if (Range.isBackward(editor.selection)) {
99
- markDefPaths.unshift(markDefPath)
100
- } else {
101
- markDefPaths.push(markDefPath)
102
- }
103
70
  }
104
71
 
105
72
  Transforms.setNodes(editor, {}, {match: Text.isText, split: true})
@@ -124,20 +91,8 @@ export const addAnnotationOperationImplementation: BehaviorOperationImplementati
124
91
  },
125
92
  {at: path},
126
93
  )
127
-
128
- spanPath = [{_key: block._key}, 'children', {_key: span._key}]
129
94
  }
130
95
 
131
96
  blockIndex++
132
97
  }
133
-
134
- if (markDefPath && spanPath) {
135
- paths = {
136
- markDefPath,
137
- markDefPaths,
138
- spanPath,
139
- }
140
- }
141
-
142
- return paths
143
98
  }
@@ -32,14 +32,13 @@ export type BehaviorOperationImplementationContext = Pick<
32
32
 
33
33
  export type BehaviorOperationImplementation<
34
34
  TBehaviorOperationType extends BehaviorOperation['type'],
35
- TReturnType = void,
36
35
  > = ({
37
36
  context,
38
37
  operation,
39
38
  }: {
40
39
  context: BehaviorOperationImplementationContext
41
40
  operation: PickFromUnion<BehaviorOperation, 'type', TBehaviorOperationType>
42
- }) => TReturnType
41
+ }) => void
43
42
 
44
43
  type BehaviorOperation = OmitFromUnion<
45
44
  SyntheticBehaviorEvent,
@@ -37,6 +37,24 @@ export interface EditableAPIDeleteOptions {
37
37
  mode?: 'blocks' | 'children' | 'selected'
38
38
  }
39
39
 
40
+ /**
41
+ * @public
42
+ */
43
+ export type AddedAnnotationPaths = {
44
+ /**
45
+ * @deprecated An annotation may be applied to multiple blocks, resulting
46
+ * in multiple `markDef`'s being created. Use `markDefPaths` instead.
47
+ */
48
+ markDefPath: Path
49
+ markDefPaths: Array<Path>
50
+ /**
51
+ * @deprecated Does not return anything meaningful since an annotation
52
+ * can span multiple blocks and spans. If references the span closest
53
+ * to the focus point of the selection.
54
+ */
55
+ spanPath: Path
56
+ }
57
+
40
58
  /** @beta */
41
59
  export interface EditableAPI {
42
60
  activeAnnotations: () => PortableTextObject[]
@@ -44,9 +62,7 @@ export interface EditableAPI {
44
62
  addAnnotation: <TSchemaType extends {name: string}>(
45
63
  type: TSchemaType,
46
64
  value?: {[prop: string]: unknown},
47
- ) =>
48
- | {markDefPath: Path; markDefPaths: Array<Path>; spanPath: Path}
49
- | undefined
65
+ ) => AddedAnnotationPaths | undefined
50
66
  blur: () => void
51
67
  delete: (
52
68
  selection: EditorSelection,