@portabletext/editor 1.12.3 → 1.13.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/lib/index.d.mts +234 -14
- package/lib/index.d.ts +234 -14
- package/lib/index.esm.js +361 -192
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +361 -192
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +361 -192
- package/lib/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/editor/Editable.tsx +60 -5
- package/src/editor/behavior/behavior.action.insert-break.ts +21 -24
- package/src/editor/behavior/behavior.actions.ts +125 -3
- package/src/editor/behavior/behavior.code-editor.ts +86 -0
- package/src/editor/behavior/behavior.core.block-objects.ts +34 -1
- package/src/editor/behavior/behavior.core.ts +2 -0
- package/src/editor/behavior/behavior.links.ts +2 -2
- package/src/editor/behavior/behavior.markdown.ts +1 -1
- package/src/editor/behavior/behavior.types.ts +37 -2
- package/src/editor/behavior/behavior.utils.ts +2 -2
- package/src/editor/editor-machine.ts +5 -2
- package/src/editor/plugins/createWithHotKeys.ts +1 -48
- package/src/index.ts +4 -0
- package/src/utils/is-hotkey.test.ts +97 -46
- package/src/utils/is-hotkey.ts +1 -1
|
@@ -71,6 +71,7 @@ export type InternalEditorEvent =
|
|
|
71
71
|
type: 'behavior event'
|
|
72
72
|
behaviorEvent: BehaviorEvent
|
|
73
73
|
editor: PortableTextSlateEditor
|
|
74
|
+
nativeEvent?: {preventDefault: () => void}
|
|
74
75
|
}
|
|
75
76
|
| {
|
|
76
77
|
type: 'behavior action intends'
|
|
@@ -271,10 +272,11 @@ export const editorMachine = setup({
|
|
|
271
272
|
|
|
272
273
|
for (const eventBehavior of eventBehaviors) {
|
|
273
274
|
const shouldRun =
|
|
274
|
-
eventBehavior.guard
|
|
275
|
+
eventBehavior.guard === undefined ||
|
|
276
|
+
eventBehavior.guard({
|
|
275
277
|
context: behaviorContext,
|
|
276
278
|
event: event.behaviorEvent,
|
|
277
|
-
})
|
|
279
|
+
})
|
|
278
280
|
|
|
279
281
|
if (!shouldRun) {
|
|
280
282
|
continue
|
|
@@ -303,6 +305,7 @@ export const editorMachine = setup({
|
|
|
303
305
|
}
|
|
304
306
|
|
|
305
307
|
if (behaviorOverwritten) {
|
|
308
|
+
event.nativeEvent?.preventDefault()
|
|
306
309
|
break
|
|
307
310
|
}
|
|
308
311
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {isPortableTextSpan, isPortableTextTextBlock} from '@sanity/types'
|
|
2
2
|
import type {KeyboardEvent} from 'react'
|
|
3
|
-
import {Editor, Node,
|
|
3
|
+
import {Editor, Node, Range} from 'slate'
|
|
4
4
|
import type {ReactEditor} from 'slate-react'
|
|
5
5
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
6
6
|
import type {HotkeyOptions} from '../../types/options'
|
|
@@ -80,53 +80,6 @@ export function createWithHotkeys(
|
|
|
80
80
|
const isTab = isHotkey('tab', event.nativeEvent)
|
|
81
81
|
const isShiftEnter = isHotkey('shift+enter', event.nativeEvent)
|
|
82
82
|
const isShiftTab = isHotkey('shift+tab', event.nativeEvent)
|
|
83
|
-
const isArrowDown = isHotkey('down', event.nativeEvent)
|
|
84
|
-
const isArrowUp = isHotkey('up', event.nativeEvent)
|
|
85
|
-
|
|
86
|
-
// Check if the user is in a void block, in that case, add an empty text block below if there is no next block
|
|
87
|
-
if (isArrowDown && editor.selection) {
|
|
88
|
-
const focusBlock = Node.descendant(
|
|
89
|
-
editor,
|
|
90
|
-
editor.selection.focus.path.slice(0, 1),
|
|
91
|
-
) as SlateTextBlock | VoidElement
|
|
92
|
-
|
|
93
|
-
if (focusBlock && Editor.isVoid(editor, focusBlock)) {
|
|
94
|
-
const nextPath = Path.next(editor.selection.focus.path.slice(0, 1))
|
|
95
|
-
const nextBlock = Node.has(editor, nextPath)
|
|
96
|
-
if (!nextBlock) {
|
|
97
|
-
Transforms.insertNodes(
|
|
98
|
-
editor,
|
|
99
|
-
editor.pteCreateTextBlock({decorators: []}),
|
|
100
|
-
{
|
|
101
|
-
at: nextPath,
|
|
102
|
-
},
|
|
103
|
-
)
|
|
104
|
-
Transforms.select(editor, {path: [...nextPath, 0], offset: 0})
|
|
105
|
-
editor.onChange()
|
|
106
|
-
return
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (isArrowUp && editor.selection) {
|
|
111
|
-
const isFirstBlock = editor.selection.focus.path[0] === 0
|
|
112
|
-
const focusBlock = Node.descendant(
|
|
113
|
-
editor,
|
|
114
|
-
editor.selection.focus.path.slice(0, 1),
|
|
115
|
-
) as SlateTextBlock | VoidElement
|
|
116
|
-
|
|
117
|
-
if (isFirstBlock && focusBlock && Editor.isVoid(editor, focusBlock)) {
|
|
118
|
-
Transforms.insertNodes(
|
|
119
|
-
editor,
|
|
120
|
-
editor.pteCreateTextBlock({decorators: []}),
|
|
121
|
-
{
|
|
122
|
-
at: [0],
|
|
123
|
-
},
|
|
124
|
-
)
|
|
125
|
-
Transforms.select(editor, {path: [0, 0], offset: 0})
|
|
126
|
-
editor.onChange()
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
83
|
|
|
131
84
|
// Tab for lists
|
|
132
85
|
// Only steal tab when we are on a plain text span or we are at the start of the line (fallback if the whole block is annotated or contains a single inline object)
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,10 @@ export {
|
|
|
9
9
|
createMarkdownBehaviors,
|
|
10
10
|
type MarkdownBehaviorsConfig,
|
|
11
11
|
} from './editor/behavior/behavior.markdown'
|
|
12
|
+
export {
|
|
13
|
+
createCodeEditorBehaviors,
|
|
14
|
+
type CodeEditorBehaviorsConfig,
|
|
15
|
+
} from './editor/behavior/behavior.code-editor'
|
|
12
16
|
export {
|
|
13
17
|
defineBehavior,
|
|
14
18
|
type Behavior,
|
|
@@ -1,61 +1,112 @@
|
|
|
1
1
|
import {expect, test} from 'vitest'
|
|
2
2
|
import {isHotkey, type KeyboardEventLike} from './is-hotkey'
|
|
3
3
|
|
|
4
|
-
function e(
|
|
4
|
+
function e(
|
|
5
|
+
value: string | number,
|
|
6
|
+
modifiers: Array<'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey'> = [],
|
|
7
|
+
) {
|
|
5
8
|
return {
|
|
6
9
|
...(typeof value === 'string' ? {key: value} : {keyCode: value}),
|
|
7
|
-
altKey: modifiers.includes('
|
|
8
|
-
ctrlKey: modifiers.includes('
|
|
9
|
-
metaKey: modifiers.includes('
|
|
10
|
-
shiftKey: modifiers.includes('
|
|
10
|
+
altKey: modifiers.includes('altKey'),
|
|
11
|
+
ctrlKey: modifiers.includes('ctrlKey'),
|
|
12
|
+
metaKey: modifiers.includes('metaKey'),
|
|
13
|
+
shiftKey: modifiers.includes('shiftKey'),
|
|
11
14
|
} as KeyboardEventLike
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
type TestCase = [
|
|
15
|
-
|
|
16
|
-
const testCases = [
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[e(
|
|
20
|
-
[e(
|
|
21
|
-
|
|
22
|
-
[e(
|
|
23
|
-
[e(
|
|
24
|
-
[e(
|
|
25
|
-
[e(
|
|
26
|
-
|
|
27
|
-
[
|
|
28
|
-
[
|
|
29
|
-
[
|
|
30
|
-
[e(
|
|
31
|
-
|
|
32
|
-
[e(
|
|
33
|
-
[e(
|
|
34
|
-
[e(83, '
|
|
35
|
-
[
|
|
36
|
-
|
|
37
|
-
[e('s', '
|
|
38
|
-
[e('s', '
|
|
39
|
-
[
|
|
40
|
-
[
|
|
41
|
-
|
|
42
|
-
[e('
|
|
43
|
-
[e('
|
|
44
|
-
[
|
|
45
|
-
[
|
|
46
|
-
|
|
47
|
-
[
|
|
48
|
-
[e('
|
|
49
|
-
[
|
|
50
|
-
[
|
|
17
|
+
type TestCase = [string, KeyboardEventLike, boolean]
|
|
18
|
+
|
|
19
|
+
const testCases: TestCase[] = [
|
|
20
|
+
['meta', e('Meta', ['metaKey']), true],
|
|
21
|
+
['Meta', e('Meta', ['metaKey']), true],
|
|
22
|
+
['meta', e(93, ['metaKey']), true],
|
|
23
|
+
['Meta', e(93, ['metaKey']), true],
|
|
24
|
+
|
|
25
|
+
['meta+s', e('s', ['metaKey']), true],
|
|
26
|
+
['Meta+S', e('s', ['metaKey']), true],
|
|
27
|
+
['meta+s', e(83, ['metaKey']), true],
|
|
28
|
+
['Meta+S', e(83, ['metaKey']), true],
|
|
29
|
+
|
|
30
|
+
['cmd+space', e(' ', ['metaKey']), true],
|
|
31
|
+
['Cmd+Space', e(' ', ['metaKey']), true],
|
|
32
|
+
['cmd+space', e(32, ['metaKey']), true],
|
|
33
|
+
['Cmd+Space', e(32, ['metaKey']), true],
|
|
34
|
+
|
|
35
|
+
['cmd+alt?+s', e('s', ['metaKey']), true],
|
|
36
|
+
['cmd+alt?+s', e('s', ['metaKey', 'altKey']), true],
|
|
37
|
+
['cmd+alt?+s', e(83, ['metaKey']), true],
|
|
38
|
+
['cmd+alt?+s', e(83, ['metaKey', 'altKey']), true],
|
|
39
|
+
|
|
40
|
+
['Cmd+Alt?+S', e('s', ['metaKey']), true],
|
|
41
|
+
['Cmd+Alt?+S', e('s', ['metaKey', 'altKey']), true],
|
|
42
|
+
['Cmd+Alt?+S', e(83, ['metaKey']), true],
|
|
43
|
+
['Cmd+Alt?+S', e(83, ['metaKey', 'altKey']), true],
|
|
44
|
+
|
|
45
|
+
['cmd+s', e('s', ['metaKey', 'altKey']), false],
|
|
46
|
+
['Cmd+S', e('s', ['metaKey', 'altKey']), false],
|
|
47
|
+
['cmd+s', e(83, ['metaKey', 'altKey']), false],
|
|
48
|
+
['Cmd+S', e(83, ['metaKey', 'altKey']), false],
|
|
49
|
+
|
|
50
|
+
['cmd+s', e('s', ['metaKey']), true],
|
|
51
|
+
['Cmd+s', e('s', ['metaKey']), true],
|
|
52
|
+
['cmd+s', e(83, ['metaKey']), true],
|
|
53
|
+
['Cmd+s', e(83, ['metaKey']), true],
|
|
54
|
+
|
|
55
|
+
['mod+s', e('s', ['ctrlKey']), true],
|
|
56
|
+
['Mod+S', e('s', ['ctrlKey']), true],
|
|
57
|
+
['mod+s', e(83, ['ctrlKey']), true],
|
|
58
|
+
['Mod+S', e(83, ['ctrlKey']), true],
|
|
59
|
+
|
|
60
|
+
['meta+alt+s', e('s', ['metaKey', 'altKey']), true],
|
|
61
|
+
['Meta+Alt+S', e('s', ['metaKey', 'altKey']), true],
|
|
62
|
+
['meta+alt+s', e(83, ['metaKey', 'altKey']), true],
|
|
63
|
+
['Meta+Alt+S', e(83, ['metaKey', 'altKey']), true],
|
|
64
|
+
|
|
65
|
+
['?', e('?'), true],
|
|
66
|
+
['?', e('?', ['altKey']), false],
|
|
67
|
+
|
|
68
|
+
['a', e('a'), true],
|
|
69
|
+
['a', e('A'), true],
|
|
70
|
+
['A', e('a'), true],
|
|
71
|
+
['A', e('A'), true],
|
|
72
|
+
['a', e(65), true],
|
|
73
|
+
['A', e(65), true],
|
|
74
|
+
|
|
75
|
+
['a', e('a', ['ctrlKey']), false],
|
|
76
|
+
['A', e('a', ['ctrlKey']), false],
|
|
77
|
+
['a', e(65, ['ctrlKey']), false],
|
|
78
|
+
['A', e(65, ['ctrlKey']), false],
|
|
79
|
+
|
|
80
|
+
['shift', e('Shift', ['shiftKey']), true],
|
|
81
|
+
['Shift', e('Shift', ['shiftKey']), true],
|
|
82
|
+
['shift', e(16, ['shiftKey']), true],
|
|
83
|
+
['Shift', e(16, ['shiftKey']), true],
|
|
84
|
+
|
|
85
|
+
['meta+a', e('a', ['metaKey']), true],
|
|
86
|
+
['Meta+A', e('a', ['metaKey']), true],
|
|
87
|
+
['cmd+a', e(65, ['metaKey']), true],
|
|
88
|
+
['Cmd+A', e(65, ['metaKey']), true],
|
|
89
|
+
|
|
90
|
+
['enter', e('Enter'), true],
|
|
91
|
+
['Enter', e('Enter'), true],
|
|
92
|
+
['enter', e(13), true],
|
|
93
|
+
['Enter', e(13), true],
|
|
94
|
+
|
|
95
|
+
['cmd+=', e(187, ['metaKey']), true],
|
|
96
|
+
['Cmd+=', e(187, ['metaKey']), true],
|
|
97
|
+
['cmd++', e('+', ['metaKey']), true],
|
|
98
|
+
['Cmd++', e('+', ['metaKey']), true],
|
|
99
|
+
|
|
100
|
+
['meta+alt+ß', e('ß', ['metaKey', 'altKey']), true],
|
|
101
|
+
['Meta+Alt+ß', e('ß', ['metaKey', 'altKey']), true],
|
|
51
102
|
] satisfies Array<TestCase>
|
|
52
103
|
|
|
53
104
|
test(isHotkey.name, () => {
|
|
54
105
|
for (const testCase of testCases) {
|
|
55
|
-
expect(isHotkey(testCase[
|
|
106
|
+
expect(isHotkey(testCase[0], testCase[1])).toBe(testCase[2])
|
|
56
107
|
}
|
|
57
108
|
|
|
58
|
-
expect(() =>
|
|
59
|
-
'
|
|
60
|
-
)
|
|
109
|
+
expect(() =>
|
|
110
|
+
isHotkey('ctrlalt+k', e('k', ['ctrlKey', 'altKey'])),
|
|
111
|
+
).toThrowError('Unknown modifier: "ctrlalt"')
|
|
61
112
|
})
|