@portabletext/editor 1.1.12 → 1.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": "1.1.12",
3
+ "version": "1.2.0",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -0,0 +1,106 @@
1
+ import {isPortableTextTextBlock} from '@sanity/types'
2
+ import {defineBehavior} from './behavior.types'
3
+ import {
4
+ getFocusBlockObject,
5
+ getFocusTextBlock,
6
+ getNextBlock,
7
+ getPreviousBlock,
8
+ isEmptyTextBlock,
9
+ selectionIsCollapsed,
10
+ } from './behavior.utils'
11
+
12
+ const breakingVoidBlock = defineBehavior({
13
+ on: 'insert break',
14
+ guard: ({context}) => {
15
+ const focusBlockObject = getFocusBlockObject(context)
16
+
17
+ return !!focusBlockObject
18
+ },
19
+ actions: [() => [{type: 'insert text block', decorators: []}]],
20
+ })
21
+
22
+ const deletingEmptyTextBlockAfterBlockObject = defineBehavior({
23
+ on: 'delete backward',
24
+ guard: ({context}) => {
25
+ const focusTextBlock = getFocusTextBlock(context)
26
+ const selectionCollapsed = selectionIsCollapsed(context)
27
+ const previousBlock = getPreviousBlock(context)
28
+
29
+ if (!focusTextBlock || !selectionCollapsed || !previousBlock) {
30
+ return false
31
+ }
32
+
33
+ if (
34
+ isEmptyTextBlock(focusTextBlock.node) &&
35
+ !isPortableTextTextBlock(previousBlock.node)
36
+ ) {
37
+ return {focusTextBlock, previousBlock}
38
+ }
39
+
40
+ return false
41
+ },
42
+ actions: [
43
+ (_, {focusTextBlock, previousBlock}) => [
44
+ {
45
+ type: 'delete',
46
+ selection: {
47
+ anchor: {path: focusTextBlock.path, offset: 0},
48
+ focus: {path: focusTextBlock.path, offset: 0},
49
+ },
50
+ },
51
+ {
52
+ type: 'select',
53
+ selection: {
54
+ anchor: {path: previousBlock.path, offset: 0},
55
+ focus: {path: previousBlock.path, offset: 0},
56
+ },
57
+ },
58
+ ],
59
+ ],
60
+ })
61
+
62
+ const deletingEmptyTextBlockBeforeBlockObject = defineBehavior({
63
+ on: 'delete forward',
64
+ guard: ({context}) => {
65
+ const focusTextBlock = getFocusTextBlock(context)
66
+ const selectionCollapsed = selectionIsCollapsed(context)
67
+ const nextBlock = getNextBlock(context)
68
+
69
+ if (!focusTextBlock || !selectionCollapsed || !nextBlock) {
70
+ return false
71
+ }
72
+
73
+ if (
74
+ isEmptyTextBlock(focusTextBlock.node) &&
75
+ !isPortableTextTextBlock(nextBlock.node)
76
+ ) {
77
+ return {focusTextBlock, nextBlock}
78
+ }
79
+
80
+ return false
81
+ },
82
+ actions: [
83
+ (_, {focusTextBlock, nextBlock}) => [
84
+ {
85
+ type: 'delete',
86
+ selection: {
87
+ anchor: {path: focusTextBlock.path, offset: 0},
88
+ focus: {path: focusTextBlock.path, offset: 0},
89
+ },
90
+ },
91
+ {
92
+ type: 'select',
93
+ selection: {
94
+ anchor: {path: nextBlock.path, offset: 0},
95
+ focus: {path: nextBlock.path, offset: 0},
96
+ },
97
+ },
98
+ ],
99
+ ],
100
+ })
101
+
102
+ export const coreBlockObjectBehaviors = [
103
+ breakingVoidBlock,
104
+ deletingEmptyTextBlockAfterBlockObject,
105
+ deletingEmptyTextBlockBeforeBlockObject,
106
+ ]
@@ -0,0 +1,76 @@
1
+ import {defineBehavior} from './behavior.types'
2
+ import {
3
+ getFocusSpan,
4
+ getFocusTextBlock,
5
+ selectionIsCollapsed,
6
+ } from './behavior.utils'
7
+
8
+ const clearListOnBackspace = defineBehavior({
9
+ on: 'delete backward',
10
+ guard: ({context}) => {
11
+ const selectionCollapsed = selectionIsCollapsed(context)
12
+ const focusTextBlock = getFocusTextBlock(context)
13
+ const focusSpan = getFocusSpan(context)
14
+
15
+ if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
16
+ return false
17
+ }
18
+
19
+ const atTheBeginningOfBLock =
20
+ focusTextBlock.node.children[0]._key === focusSpan.node._key &&
21
+ context.selection.focus.offset === 0
22
+
23
+ if (atTheBeginningOfBLock && focusTextBlock.node.level === 1) {
24
+ return {focusTextBlock}
25
+ }
26
+
27
+ return false
28
+ },
29
+ actions: [
30
+ (_, {focusTextBlock}) => [
31
+ {
32
+ type: 'unset block',
33
+ props: ['listItem', 'level'],
34
+ paths: [focusTextBlock.path],
35
+ },
36
+ ],
37
+ ],
38
+ })
39
+
40
+ const unindentListOnBackspace = defineBehavior({
41
+ on: 'delete backward',
42
+ guard: ({context}) => {
43
+ const selectionCollapsed = selectionIsCollapsed(context)
44
+ const focusTextBlock = getFocusTextBlock(context)
45
+ const focusSpan = getFocusSpan(context)
46
+
47
+ if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
48
+ return false
49
+ }
50
+
51
+ const atTheBeginningOfBLock =
52
+ focusTextBlock.node.children[0]._key === focusSpan.node._key &&
53
+ context.selection.focus.offset === 0
54
+
55
+ if (
56
+ atTheBeginningOfBLock &&
57
+ focusTextBlock.node.level !== undefined &&
58
+ focusTextBlock.node.level > 1
59
+ ) {
60
+ return {focusTextBlock, level: focusTextBlock.node.level - 1}
61
+ }
62
+
63
+ return false
64
+ },
65
+ actions: [
66
+ (_, {focusTextBlock, level}) => [
67
+ {
68
+ type: 'set block',
69
+ level,
70
+ paths: [focusTextBlock.path],
71
+ },
72
+ ],
73
+ ],
74
+ })
75
+
76
+ export const coreListBehaviors = [clearListOnBackspace, unindentListOnBackspace]
@@ -1,112 +1,14 @@
1
- import {isPortableTextTextBlock} from '@sanity/types'
1
+ import {coreBlockObjectBehaviors} from './behavior.core.block-objects'
2
+ import {coreListBehaviors} from './behavior.core.lists'
2
3
  import {defineBehavior} from './behavior.types'
3
- import {
4
- getFocusBlockObject,
5
- getFocusTextBlock,
6
- getNextBlock,
7
- getPreviousBlock,
8
- isEmptyTextBlock,
9
- selectionIsCollapsed,
10
- } from './behavior.utils'
11
4
 
12
5
  const softReturn = defineBehavior({
13
6
  on: 'insert soft break',
14
7
  actions: [() => [{type: 'insert text', text: '\n'}]],
15
8
  })
16
9
 
17
- const breakingVoidBlock = defineBehavior({
18
- on: 'insert break',
19
- guard: ({context}) => {
20
- const focusBlockObject = getFocusBlockObject(context)
21
-
22
- return !!focusBlockObject
23
- },
24
- actions: [() => [{type: 'insert text block', decorators: []}]],
25
- })
26
-
27
- const deletingEmptyTextBlockAfterBlockObject = defineBehavior({
28
- on: 'delete backward',
29
- guard: ({context}) => {
30
- const focusTextBlock = getFocusTextBlock(context)
31
- const selectionCollapsed = selectionIsCollapsed(context)
32
- const previousBlock = getPreviousBlock(context)
33
-
34
- if (!focusTextBlock || !selectionCollapsed || !previousBlock) {
35
- return false
36
- }
37
-
38
- if (
39
- isEmptyTextBlock(focusTextBlock.node) &&
40
- !isPortableTextTextBlock(previousBlock.node)
41
- ) {
42
- return {focusTextBlock, previousBlock}
43
- }
44
-
45
- return false
46
- },
47
- actions: [
48
- (_, {focusTextBlock, previousBlock}) => [
49
- {
50
- type: 'delete',
51
- selection: {
52
- anchor: {path: focusTextBlock.path, offset: 0},
53
- focus: {path: focusTextBlock.path, offset: 0},
54
- },
55
- },
56
- {
57
- type: 'select',
58
- selection: {
59
- anchor: {path: previousBlock.path, offset: 0},
60
- focus: {path: previousBlock.path, offset: 0},
61
- },
62
- },
63
- ],
64
- ],
65
- })
66
-
67
- const deletingEmptyTextBlockBeforeBlockObject = defineBehavior({
68
- on: 'delete forward',
69
- guard: ({context}) => {
70
- const focusTextBlock = getFocusTextBlock(context)
71
- const selectionCollapsed = selectionIsCollapsed(context)
72
- const nextBlock = getNextBlock(context)
73
-
74
- if (!focusTextBlock || !selectionCollapsed || !nextBlock) {
75
- return false
76
- }
77
-
78
- if (
79
- isEmptyTextBlock(focusTextBlock.node) &&
80
- !isPortableTextTextBlock(nextBlock.node)
81
- ) {
82
- return {focusTextBlock, nextBlock}
83
- }
84
-
85
- return false
86
- },
87
- actions: [
88
- (_, {focusTextBlock, nextBlock}) => [
89
- {
90
- type: 'delete',
91
- selection: {
92
- anchor: {path: focusTextBlock.path, offset: 0},
93
- focus: {path: focusTextBlock.path, offset: 0},
94
- },
95
- },
96
- {
97
- type: 'select',
98
- selection: {
99
- anchor: {path: nextBlock.path, offset: 0},
100
- focus: {path: nextBlock.path, offset: 0},
101
- },
102
- },
103
- ],
104
- ],
105
- })
106
-
107
10
  export const coreBehaviors = [
108
11
  softReturn,
109
- breakingVoidBlock,
110
- deletingEmptyTextBlockAfterBlockObject,
111
- deletingEmptyTextBlockBeforeBlockObject,
12
+ ...coreBlockObjectBehaviors,
13
+ ...coreListBehaviors,
112
14
  ]