@portabletext/editor 3.1.2 → 3.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "3.1.2",
3
+ "version": "3.2.0",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -75,12 +75,13 @@
75
75
  "xstate": "^5.24.0",
76
76
  "@portabletext/block-tools": "^4.1.4",
77
77
  "@portabletext/keyboard-shortcuts": "^2.1.0",
78
+ "@portabletext/markdown": "^1.0.1",
78
79
  "@portabletext/patches": "^2.0.0",
79
80
  "@portabletext/schema": "^2.0.0"
80
81
  },
81
82
  "devDependencies": {
82
83
  "@sanity/diff-match-patch": "^3.2.0",
83
- "@sanity/pkg-utils": "^9.0.3",
84
+ "@sanity/pkg-utils": "^10.0.0",
84
85
  "@sanity/schema": "^4.20.0",
85
86
  "@sanity/types": "^4.20.0",
86
87
  "@types/debug": "^4.1.12",
@@ -35,6 +35,18 @@ export const abstractDeserializeBehaviors = [
35
35
  } as const
36
36
  }
37
37
 
38
+ const markdown =
39
+ event.originEvent.originEvent.dataTransfer.getData('text/markdown')
40
+
41
+ if (markdown) {
42
+ return {
43
+ type: 'deserialize.data',
44
+ mimeType: 'text/markdown',
45
+ data: markdown,
46
+ originEvent: event.originEvent,
47
+ } as const
48
+ }
49
+
38
50
  const html =
39
51
  event.originEvent.originEvent.dataTransfer.getData('text/html')
40
52
 
@@ -199,6 +211,20 @@ export const abstractDeserializeBehaviors = [
199
211
  }
200
212
 
201
213
  if (event.mimeType === 'application/json') {
214
+ const markdown =
215
+ event.originEvent.originEvent.dataTransfer.getData('text/markdown')
216
+
217
+ if (markdown) {
218
+ return {
219
+ type: 'deserialize.data',
220
+ mimeType: 'text/markdown',
221
+ data: markdown,
222
+ originEvent: event.originEvent,
223
+ } as const
224
+ }
225
+ }
226
+
227
+ if (event.mimeType === 'text/markdown') {
202
228
  const html =
203
229
  event.originEvent.originEvent.dataTransfer.getData('text/html')
204
230
 
@@ -16,6 +16,11 @@ export const abstractSerializeBehaviors = [
16
16
  mimeType: 'application/json',
17
17
  originEvent: event.originEvent,
18
18
  }),
19
+ raise({
20
+ type: 'serialize.data',
21
+ mimeType: 'text/markdown',
22
+ originEvent: event.originEvent,
23
+ }),
19
24
  raise({
20
25
  type: 'serialize.data',
21
26
  mimeType: 'text/html',
@@ -19,8 +19,8 @@ export type Behavior<
19
19
  | `${BehaviorEventTypeNamespace}.*`
20
20
  | BehaviorEvent['type'],
21
21
  TGuardResponse = true,
22
- TBehaviorEvent extends
23
- ResolveBehaviorEvent<TBehaviorEventType> = ResolveBehaviorEvent<TBehaviorEventType>,
22
+ TBehaviorEvent extends ResolveBehaviorEvent<TBehaviorEventType> =
23
+ ResolveBehaviorEvent<TBehaviorEventType>,
24
24
  > = {
25
25
  /**
26
26
  * Editor Event that triggers this Behavior.
@@ -74,10 +74,8 @@ export function defineBehavior<
74
74
  | `${BehaviorEventTypeNamespace}.*`
75
75
  | BehaviorEvent['type'] = BehaviorEvent['type'],
76
76
  TGuardResponse = true,
77
- TBehaviorEvent extends ResolveBehaviorEvent<
78
- TBehaviorEventType,
79
- TPayload
80
- > = ResolveBehaviorEvent<TBehaviorEventType, TPayload>,
77
+ TBehaviorEvent extends ResolveBehaviorEvent<TBehaviorEventType, TPayload> =
78
+ ResolveBehaviorEvent<TBehaviorEventType, TPayload>,
81
79
  >(
82
80
  behavior: Behavior<TBehaviorEventType, TGuardResponse, TBehaviorEvent>,
83
81
  ): Behavior {
@@ -625,10 +625,8 @@ type CustomBehaviorEventType<
625
625
  export type CustomBehaviorEvent<
626
626
  TPayload extends Record<string, unknown> = Record<string, unknown>,
627
627
  TType extends string = string,
628
- TInternalType extends CustomBehaviorEventType<
629
- 'custom',
630
- TType
631
- > = CustomBehaviorEventType<'custom', TType>,
628
+ TInternalType extends CustomBehaviorEventType<'custom', TType> =
629
+ CustomBehaviorEventType<'custom', TType>,
632
630
  > = {
633
631
  type: TInternalType
634
632
  } & TPayload
@@ -0,0 +1,67 @@
1
+ import {
2
+ markdownToPortableText,
3
+ portableTextToMarkdown,
4
+ } from '@portabletext/markdown'
5
+ import {getSelectedValue} from '../selectors/selector.get-selected-value'
6
+ import {parseBlock} from '../utils/parse-blocks'
7
+ import {defineConverter} from './converter.types'
8
+
9
+ export const converterTextMarkdown = defineConverter({
10
+ mimeType: 'text/markdown',
11
+ serialize: ({snapshot, event}) => {
12
+ const selection = snapshot.context.selection
13
+
14
+ if (!selection) {
15
+ return {
16
+ type: 'serialization.failure',
17
+ mimeType: 'text/markdown',
18
+ reason: 'No selection',
19
+ originEvent: event.originEvent,
20
+ }
21
+ }
22
+
23
+ const blocks = getSelectedValue(snapshot)
24
+
25
+ const markdown = portableTextToMarkdown(blocks)
26
+
27
+ return {
28
+ type: 'serialization.success',
29
+ data: markdown,
30
+ mimeType: 'text/markdown',
31
+ originEvent: event.originEvent,
32
+ }
33
+ },
34
+ deserialize: ({snapshot, event}) => {
35
+ const blocks = markdownToPortableText(event.data, {
36
+ keyGenerator: snapshot.context.keyGenerator,
37
+ schema: snapshot.context.schema,
38
+ })
39
+
40
+ const parsedBlocks = blocks.flatMap((block) => {
41
+ const parsedBlock = parseBlock({
42
+ context: snapshot.context,
43
+ block,
44
+ options: {
45
+ normalize: false,
46
+ removeUnusedMarkDefs: true,
47
+ validateFields: false,
48
+ },
49
+ })
50
+ return parsedBlock ? [parsedBlock] : []
51
+ })
52
+
53
+ if (parsedBlocks.length === 0) {
54
+ return {
55
+ type: 'deserialization.failure',
56
+ mimeType: 'text/markdown',
57
+ reason: 'No blocks deserialized',
58
+ }
59
+ }
60
+
61
+ return {
62
+ type: 'deserialization.success',
63
+ data: parsedBlocks,
64
+ mimeType: 'text/markdown',
65
+ }
66
+ },
67
+ })
@@ -2,6 +2,7 @@ import type {PortableTextMemberSchemaTypes} from '../types/editor'
2
2
  import {converterJson} from './converter.json'
3
3
  import {converterPortableText} from './converter.portable-text'
4
4
  import {createConverterTextHtml} from './converter.text-html'
5
+ import {converterTextMarkdown} from './converter.text-markdown'
5
6
  import {createConverterTextPlain} from './converter.text-plain'
6
7
 
7
8
  export function createCoreConverters(
@@ -10,6 +11,7 @@ export function createCoreConverters(
10
11
  return [
11
12
  converterJson,
12
13
  converterPortableText,
14
+ converterTextMarkdown,
13
15
  createConverterTextHtml(legacySchema),
14
16
  createConverterTextPlain(legacySchema),
15
17
  ]
@@ -11,8 +11,10 @@ export interface VoidElement {
11
11
  value: Record<string, unknown>
12
12
  }
13
13
 
14
- export interface SlateTextBlock
15
- extends Omit<PortableTextTextBlock, 'children'> {
14
+ export interface SlateTextBlock extends Omit<
15
+ PortableTextTextBlock,
16
+ 'children'
17
+ > {
16
18
  children: Descendant[]
17
19
  }
18
20
 
@@ -5,10 +5,10 @@ import type {EditorSelection, EditorSelectionPoint} from '../types/editor'
5
5
  */
6
6
  export function getSelectionEndPoint<
7
7
  TEditorSelection extends NonNullable<EditorSelection> | null,
8
- TEditorSelectionPoint extends
9
- EditorSelectionPoint | null = TEditorSelection extends NonNullable<EditorSelection>
10
- ? EditorSelectionPoint
11
- : null,
8
+ TEditorSelectionPoint extends EditorSelectionPoint | null =
9
+ TEditorSelection extends NonNullable<EditorSelection>
10
+ ? EditorSelectionPoint
11
+ : null,
12
12
  >(selection: TEditorSelection): TEditorSelectionPoint {
13
13
  if (!selection) {
14
14
  return null as TEditorSelectionPoint
@@ -5,10 +5,10 @@ import type {EditorSelection, EditorSelectionPoint} from '../types/editor'
5
5
  */
6
6
  export function getSelectionStartPoint<
7
7
  TEditorSelection extends NonNullable<EditorSelection> | null,
8
- TEditorSelectionPoint extends
9
- EditorSelectionPoint | null = TEditorSelection extends NonNullable<EditorSelection>
10
- ? EditorSelectionPoint
11
- : null,
8
+ TEditorSelectionPoint extends EditorSelectionPoint | null =
9
+ TEditorSelection extends NonNullable<EditorSelection>
10
+ ? EditorSelectionPoint
11
+ : null,
12
12
  >(selection: TEditorSelection): TEditorSelectionPoint {
13
13
  if (!selection) {
14
14
  return null as TEditorSelectionPoint