@portabletext/editor 1.12.3 → 1.14.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/README.md +1 -1
- package/lib/_chunks-cjs/selector.get-text-before.cjs +320 -0
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -0
- package/lib/_chunks-es/selector.get-text-before.js +321 -0
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -0
- package/lib/{index.esm.js → index.cjs} +1954 -1513
- package/lib/index.cjs.map +1 -0
- package/lib/{index.d.mts → index.d.cts} +4249 -304
- package/lib/index.d.ts +4249 -304
- package/lib/index.js +1974 -1488
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +35 -0
- package/lib/selectors/index.cjs.map +1 -0
- package/lib/selectors/index.d.cts +243 -0
- package/lib/selectors/index.d.ts +243 -0
- package/lib/selectors/index.js +36 -0
- package/lib/selectors/index.js.map +1 -0
- package/package.json +25 -17
- package/src/editor/Editable.tsx +61 -6
- package/src/editor/PortableTextEditor.tsx +19 -4
- package/src/editor/__tests__/handleClick.test.tsx +4 -4
- package/src/editor/behavior/behavior.action.insert-block-object.ts +1 -1
- package/src/editor/behavior/behavior.action.insert-break.ts +24 -27
- package/src/editor/behavior/behavior.action.insert-inline-object.ts +58 -0
- package/src/editor/behavior/behavior.action.insert-span.ts +1 -1
- package/src/editor/behavior/behavior.action.list-item.ts +100 -0
- package/src/editor/behavior/behavior.action.style.ts +108 -0
- package/src/editor/behavior/behavior.action.text-block.set.ts +25 -0
- package/src/editor/behavior/behavior.action.text-block.unset.ts +17 -0
- package/src/editor/behavior/behavior.actions.ts +266 -75
- package/src/editor/behavior/behavior.code-editor.ts +76 -0
- package/src/editor/behavior/behavior.core.block-objects.ts +52 -19
- package/src/editor/behavior/behavior.core.decorators.ts +9 -6
- package/src/editor/behavior/behavior.core.lists.ts +139 -17
- package/src/editor/behavior/behavior.core.ts +7 -2
- package/src/editor/behavior/behavior.guards.ts +28 -0
- package/src/editor/behavior/behavior.links.ts +9 -9
- package/src/editor/behavior/behavior.markdown.ts +69 -80
- package/src/editor/behavior/behavior.types.ts +121 -60
- package/src/editor/{use-editor.ts → create-editor.ts} +13 -8
- package/src/editor/editor-event-listener.tsx +2 -2
- package/src/editor/editor-machine.ts +57 -15
- package/src/editor/editor-provider.tsx +5 -5
- package/src/editor/editor-selector.ts +49 -0
- package/src/editor/editor-snapshot.ts +22 -0
- package/src/editor/get-value.ts +11 -0
- package/src/editor/plugins/create-with-event-listeners.ts +93 -5
- package/src/editor/plugins/createWithEditableAPI.ts +69 -20
- package/src/editor/plugins/createWithHotKeys.ts +0 -101
- package/src/editor/plugins/createWithPortableTextBlockStyle.ts +1 -55
- package/src/editor/plugins/with-plugins.ts +4 -8
- package/src/editor/{behavior/behavior.utils.block-offset.test.ts → utils/utils.block-offset.test.ts} +1 -1
- package/src/editor/{behavior/behavior.utils.block-offset.ts → utils/utils.block-offset.ts} +1 -8
- package/src/editor/{behavior/behavior.utils.reverse-selection.ts → utils/utils.reverse-selection.ts} +3 -5
- package/src/editor/utils/utils.ts +21 -0
- package/src/index.ts +13 -9
- package/src/selectors/index.ts +15 -0
- package/src/selectors/selector.get-active-list-item.ts +37 -0
- package/src/{editor/behavior/behavior.utils.get-selection-text.ts → selectors/selector.get-selection-text.ts} +10 -15
- package/src/selectors/selector.get-text-before.ts +41 -0
- package/src/selectors/selectors.ts +329 -0
- package/src/types/editor.ts +0 -60
- package/src/utils/is-hotkey.test.ts +99 -46
- package/src/utils/is-hotkey.ts +1 -1
- package/src/utils/operationToPatches.ts +5 -0
- package/src/utils/paths.ts +4 -11
- package/src/utils/ranges.ts +3 -3
- package/lib/index.esm.js.map +0 -1
- package/lib/index.mjs +0 -7372
- package/lib/index.mjs.map +0 -1
- package/src/editor/behavior/behavior.utils.ts +0 -218
- package/src/editor/behavior/behavior.utilts.get-text-before.ts +0 -31
- package/src/editor/plugins/createWithPortableTextLists.ts +0 -172
- /package/src/editor/{behavior/behavior.utils.get-start-point.ts → utils/utils.get-start-point.ts} +0 -0
- /package/src/editor/{behavior/behavior.utils.is-keyed-segment.ts → utils/utils.is-keyed-segment.ts} +0 -0
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {isPortableTextSpan, isPortableTextTextBlock} from '@sanity/types'
|
|
2
1
|
import type {KeyboardEvent} from 'react'
|
|
3
|
-
import {Editor, Node, Path, Range, Transforms} from 'slate'
|
|
4
2
|
import type {ReactEditor} from 'slate-react'
|
|
5
3
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
6
4
|
import type {HotkeyOptions} from '../../types/options'
|
|
7
|
-
import type {SlateTextBlock, VoidElement} from '../../types/slate'
|
|
8
5
|
import {debugWithName} from '../../utils/debug'
|
|
9
6
|
import {isHotkey} from '../../utils/is-hotkey'
|
|
10
7
|
import type {EditorActor} from '../editor-machine'
|
|
@@ -75,104 +72,6 @@ export function createWithHotkeys(
|
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
})
|
|
78
|
-
|
|
79
|
-
const isEnter = isHotkey('enter', event.nativeEvent)
|
|
80
|
-
const isTab = isHotkey('tab', event.nativeEvent)
|
|
81
|
-
const isShiftEnter = isHotkey('shift+enter', event.nativeEvent)
|
|
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
|
-
|
|
131
|
-
// Tab for lists
|
|
132
|
-
// 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)
|
|
133
|
-
// Otherwise tab is reserved for accessability for buttons etc.
|
|
134
|
-
if ((isTab || isShiftTab) && editor.selection) {
|
|
135
|
-
const [focusChild] = Editor.node(editor, editor.selection.focus, {
|
|
136
|
-
depth: 2,
|
|
137
|
-
})
|
|
138
|
-
const [focusBlock] = isPortableTextSpan(focusChild)
|
|
139
|
-
? Editor.node(editor, editor.selection.focus, {depth: 1})
|
|
140
|
-
: []
|
|
141
|
-
const hasAnnotationFocus =
|
|
142
|
-
focusChild &&
|
|
143
|
-
isPortableTextTextBlock(focusBlock) &&
|
|
144
|
-
isPortableTextSpan(focusChild) &&
|
|
145
|
-
(focusChild.marks || ([] as string[])).filter((m) =>
|
|
146
|
-
(focusBlock.markDefs || []).map((def) => def._key).includes(m),
|
|
147
|
-
).length > 0
|
|
148
|
-
const [start] = Range.edges(editor.selection)
|
|
149
|
-
const atStartOfNode = Editor.isStart(editor, start, start.path)
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
focusChild &&
|
|
153
|
-
isPortableTextSpan(focusChild) &&
|
|
154
|
-
(!hasAnnotationFocus || atStartOfNode) &&
|
|
155
|
-
editor.pteIncrementBlockLevels(isShiftTab)
|
|
156
|
-
) {
|
|
157
|
-
event.preventDefault()
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Deal with enter key combos
|
|
162
|
-
if (isEnter && !isShiftEnter && editor.selection) {
|
|
163
|
-
const focusBlockPath = editor.selection.focus.path.slice(0, 1)
|
|
164
|
-
const focusBlock = Node.descendant(editor, focusBlockPath) as
|
|
165
|
-
| SlateTextBlock
|
|
166
|
-
| VoidElement
|
|
167
|
-
|
|
168
|
-
// List item enter key
|
|
169
|
-
if (editor.isListBlock(focusBlock)) {
|
|
170
|
-
if (editor.pteEndList()) {
|
|
171
|
-
event.preventDefault()
|
|
172
|
-
}
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
75
|
}
|
|
177
76
|
return editor
|
|
178
77
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Editor, Path, Text as SlateText, Transforms
|
|
1
|
+
import {Editor, Path, Text as SlateText, Transforms} from 'slate'
|
|
2
2
|
import type {
|
|
3
3
|
PortableTextMemberSchemaTypes,
|
|
4
4
|
PortableTextSlateEditor,
|
|
@@ -50,60 +50,6 @@ export function createWithPortableTextBlockStyle(
|
|
|
50
50
|
normalizeNode(nodeEntry)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
editor.pteHasBlockStyle = (style: string): boolean => {
|
|
54
|
-
if (!editor.selection) {
|
|
55
|
-
return false
|
|
56
|
-
}
|
|
57
|
-
const selectedBlocks = [
|
|
58
|
-
...Editor.nodes(editor, {
|
|
59
|
-
at: editor.selection,
|
|
60
|
-
match: (node) => editor.isTextBlock(node) && node.style === style,
|
|
61
|
-
}),
|
|
62
|
-
]
|
|
63
|
-
if (selectedBlocks.length > 0) {
|
|
64
|
-
return true
|
|
65
|
-
}
|
|
66
|
-
return false
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
editor.pteToggleBlockStyle = (blockStyle: string): void => {
|
|
70
|
-
if (!editor.selection) {
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
const selectedBlocks = [
|
|
74
|
-
...Editor.nodes(editor, {
|
|
75
|
-
at: editor.selection,
|
|
76
|
-
match: (node) => editor.isTextBlock(node),
|
|
77
|
-
}),
|
|
78
|
-
]
|
|
79
|
-
selectedBlocks.forEach(([node, path]) => {
|
|
80
|
-
if (editor.isTextBlock(node) && node.style === blockStyle) {
|
|
81
|
-
debug(`Unsetting block style '${blockStyle}'`)
|
|
82
|
-
Transforms.setNodes(
|
|
83
|
-
editor,
|
|
84
|
-
{...node, style: defaultStyle} as Partial<Node>,
|
|
85
|
-
{
|
|
86
|
-
at: path,
|
|
87
|
-
},
|
|
88
|
-
)
|
|
89
|
-
} else {
|
|
90
|
-
if (blockStyle) {
|
|
91
|
-
debug(`Setting style '${blockStyle}'`)
|
|
92
|
-
} else {
|
|
93
|
-
debug('Setting default style', defaultStyle)
|
|
94
|
-
}
|
|
95
|
-
Transforms.setNodes(
|
|
96
|
-
editor,
|
|
97
|
-
{
|
|
98
|
-
...node,
|
|
99
|
-
style: blockStyle || defaultStyle,
|
|
100
|
-
} as Partial<Node>,
|
|
101
|
-
{at: path},
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
editor.onChange()
|
|
106
|
-
}
|
|
107
53
|
return editor
|
|
108
54
|
}
|
|
109
55
|
}
|
|
@@ -8,7 +8,6 @@ import {createWithObjectKeys} from './createWithObjectKeys'
|
|
|
8
8
|
import {createWithPatches} from './createWithPatches'
|
|
9
9
|
import {createWithPlaceholderBlock} from './createWithPlaceholderBlock'
|
|
10
10
|
import {createWithPortableTextBlockStyle} from './createWithPortableTextBlockStyle'
|
|
11
|
-
import {createWithPortableTextLists} from './createWithPortableTextLists'
|
|
12
11
|
import {createWithPortableTextMarkModel} from './createWithPortableTextMarkModel'
|
|
13
12
|
import {createWithPortableTextSelections} from './createWithPortableTextSelections'
|
|
14
13
|
import {createWithSchemaTypes} from './createWithSchemaTypes'
|
|
@@ -46,7 +45,6 @@ export const withPlugins = <T extends Editor>(
|
|
|
46
45
|
subscriptions: options.subscriptions,
|
|
47
46
|
})
|
|
48
47
|
const withMaxBlocks = createWithMaxBlocks(editorActor)
|
|
49
|
-
const withPortableTextLists = createWithPortableTextLists(schemaTypes)
|
|
50
48
|
const withUndoRedo = createWithUndoRedo({
|
|
51
49
|
editorActor,
|
|
52
50
|
blockSchemaType: schemaTypes.block,
|
|
@@ -82,12 +80,10 @@ export const withPlugins = <T extends Editor>(
|
|
|
82
80
|
withObjectKeys(
|
|
83
81
|
withPortableTextMarkModel(
|
|
84
82
|
withPortableTextBlockStyle(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
withUndoRedo(withPatches(withPortableTextSelections(e))),
|
|
90
|
-
),
|
|
83
|
+
withPlaceholderBlock(
|
|
84
|
+
withUtils(
|
|
85
|
+
withMaxBlocks(
|
|
86
|
+
withUndoRedo(withPatches(withPortableTextSelections(e))),
|
|
91
87
|
),
|
|
92
88
|
),
|
|
93
89
|
),
|
package/src/editor/{behavior/behavior.utils.block-offset.test.ts → utils/utils.block-offset.test.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {PortableTextBlock} from '@sanity/types'
|
|
2
2
|
import {expect, test} from 'vitest'
|
|
3
|
-
import {blockOffsetToSpanSelectionPoint} from './
|
|
3
|
+
import {blockOffsetToSpanSelectionPoint} from './utils.block-offset'
|
|
4
4
|
|
|
5
5
|
test(blockOffsetToSpanSelectionPoint.name, () => {
|
|
6
6
|
const value: Array<PortableTextBlock> = [
|
|
@@ -4,14 +4,7 @@ import {
|
|
|
4
4
|
type KeyedSegment,
|
|
5
5
|
type PortableTextBlock,
|
|
6
6
|
} from '@sanity/types'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @alpha
|
|
10
|
-
*/
|
|
11
|
-
export type BlockOffset = {
|
|
12
|
-
path: [KeyedSegment]
|
|
13
|
-
offset: number
|
|
14
|
-
}
|
|
7
|
+
import type {BlockOffset} from '../behavior/behavior.types'
|
|
15
8
|
|
|
16
9
|
export function blockOffsetToSpanSelectionPoint({
|
|
17
10
|
value,
|
package/src/editor/{behavior/behavior.utils.reverse-selection.ts → utils/utils.reverse-selection.ts}
RENAMED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type {EditorSelection} from '../../types/editor'
|
|
2
2
|
|
|
3
|
-
export function reverseSelection(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
3
|
+
export function reverseSelection(
|
|
4
|
+
selection: NonNullable<EditorSelection>,
|
|
5
|
+
): NonNullable<EditorSelection> {
|
|
8
6
|
if (selection.backward) {
|
|
9
7
|
return {
|
|
10
8
|
anchor: selection.focus,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isPortableTextSpan,
|
|
3
|
+
isPortableTextTextBlock,
|
|
4
|
+
type PortableTextBlock,
|
|
5
|
+
type PortableTextTextBlock,
|
|
6
|
+
} from '@sanity/types'
|
|
7
|
+
|
|
8
|
+
export function isEmptyTextBlock(block: PortableTextBlock) {
|
|
9
|
+
if (!isPortableTextTextBlock(block)) {
|
|
10
|
+
return false
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const onlyText = block.children.every(isPortableTextSpan)
|
|
14
|
+
const blockText = getTextBlockText(block)
|
|
15
|
+
|
|
16
|
+
return onlyText && blockText === ''
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getTextBlockText(block: PortableTextTextBlock) {
|
|
20
|
+
return block.children.map((child) => child.text ?? '').join('')
|
|
21
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export type {Patch} from '@portabletext/patches'
|
|
2
2
|
export type {PortableTextBlock, PortableTextChild} from '@sanity/types'
|
|
3
|
+
export {
|
|
4
|
+
createCodeEditorBehaviors,
|
|
5
|
+
type CodeEditorBehaviorsConfig,
|
|
6
|
+
} from './editor/behavior/behavior.code-editor'
|
|
3
7
|
export {coreBehavior, coreBehaviors} from './editor/behavior/behavior.core'
|
|
4
8
|
export {
|
|
5
9
|
createLinkBehaviors,
|
|
@@ -14,13 +18,13 @@ export {
|
|
|
14
18
|
type Behavior,
|
|
15
19
|
type BehaviorActionIntend,
|
|
16
20
|
type BehaviorActionIntendSet,
|
|
17
|
-
type BehaviorContext,
|
|
18
21
|
type BehaviorEvent,
|
|
19
22
|
type BehaviorGuard,
|
|
20
23
|
type OmitFromUnion,
|
|
21
24
|
type PickFromUnion,
|
|
25
|
+
type BlockOffset,
|
|
22
26
|
} from './editor/behavior/behavior.types'
|
|
23
|
-
export type {
|
|
27
|
+
export type {Editor, EditorConfig, EditorEvent} from './editor/create-editor'
|
|
24
28
|
export type {SlateEditor} from './editor/create-slate-editor'
|
|
25
29
|
export {
|
|
26
30
|
defineSchema,
|
|
@@ -42,20 +46,20 @@ export {
|
|
|
42
46
|
} from './editor/editor-machine'
|
|
43
47
|
export {
|
|
44
48
|
EditorProvider,
|
|
45
|
-
|
|
49
|
+
useEditor,
|
|
46
50
|
type EditorProviderProps,
|
|
47
51
|
} from './editor/editor-provider'
|
|
52
|
+
export {
|
|
53
|
+
useEditorSelector,
|
|
54
|
+
type EditorSelector,
|
|
55
|
+
type EditorSelectorSnapshot,
|
|
56
|
+
} from './editor/editor-selector'
|
|
57
|
+
export type {EditorContext, EditorSnapshot} from './editor/editor-snapshot'
|
|
48
58
|
export {usePortableTextEditor} from './editor/hooks/usePortableTextEditor'
|
|
49
59
|
export {usePortableTextEditorSelection} from './editor/hooks/usePortableTextEditorSelection'
|
|
50
60
|
export {defaultKeyGenerator as keyGenerator} from './editor/key-generator'
|
|
51
61
|
export type {AddedAnnotationPaths} from './editor/plugins/createWithEditableAPI'
|
|
52
62
|
export {PortableTextEditor} from './editor/PortableTextEditor'
|
|
53
63
|
export type {PortableTextEditorProps} from './editor/PortableTextEditor'
|
|
54
|
-
export {
|
|
55
|
-
useEditor,
|
|
56
|
-
type Editor,
|
|
57
|
-
type EditorConfig,
|
|
58
|
-
type EditorEvent,
|
|
59
|
-
} from './editor/use-editor'
|
|
60
64
|
export * from './types/editor'
|
|
61
65
|
export type {HotkeyOptions} from './types/options'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
EditorSelector,
|
|
3
|
+
EditorSelectorSnapshot,
|
|
4
|
+
} from '../editor/editor-selector'
|
|
5
|
+
export type {EditorContext, EditorSnapshot} from '../editor/editor-snapshot'
|
|
6
|
+
export type {
|
|
7
|
+
EditorSelection,
|
|
8
|
+
EditorSelectionPoint,
|
|
9
|
+
PortableTextMemberSchemaTypes,
|
|
10
|
+
} from '../types/editor'
|
|
11
|
+
|
|
12
|
+
export {getActiveListItem} from './selector.get-active-list-item'
|
|
13
|
+
export {getSelectionText} from './selector.get-selection-text'
|
|
14
|
+
export {getBlockTextBefore} from './selector.get-text-before'
|
|
15
|
+
export * from './selectors'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type {PortableTextListBlock} from '@sanity/types'
|
|
2
|
+
import {createGuards} from '../editor/behavior/behavior.guards'
|
|
3
|
+
import type {EditorSelector} from '../editor/editor-selector'
|
|
4
|
+
import {getSelectedBlocks} from './selectors'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @alpha
|
|
8
|
+
*/
|
|
9
|
+
export const getActiveListItem: EditorSelector<
|
|
10
|
+
PortableTextListBlock['listItem'] | undefined
|
|
11
|
+
> = ({context}) => {
|
|
12
|
+
if (!context.selection) {
|
|
13
|
+
return undefined
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const guards = createGuards(context)
|
|
17
|
+
const selectedBlocks = getSelectedBlocks({context}).map((block) => block.node)
|
|
18
|
+
const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)
|
|
19
|
+
|
|
20
|
+
const firstTextBlock = selectedTextBlocks.at(0)
|
|
21
|
+
|
|
22
|
+
if (!firstTextBlock) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const firstListItem = firstTextBlock.listItem
|
|
27
|
+
|
|
28
|
+
if (!firstListItem) {
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (selectedTextBlocks.every((block) => block.listItem === firstListItem)) {
|
|
33
|
+
return firstListItem
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return undefined
|
|
37
|
+
}
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from '@sanity/types'
|
|
6
|
-
import type {EditorSelection} from '../../types/editor'
|
|
7
|
-
import {isKeyedSegment} from './behavior.utils.is-keyed-segment'
|
|
8
|
-
import {reverseSelection} from './behavior.utils.reverse-selection'
|
|
1
|
+
import {isPortableTextSpan, isPortableTextTextBlock} from '@sanity/types'
|
|
2
|
+
import type {EditorSelector} from '../editor/editor-selector'
|
|
3
|
+
import {isKeyedSegment} from '../editor/utils/utils.is-keyed-segment'
|
|
4
|
+
import {reverseSelection} from '../editor/utils/utils.reverse-selection'
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
value: Array<PortableTextBlock>
|
|
15
|
-
selection: NonNullable<EditorSelection>
|
|
16
|
-
}): string {
|
|
6
|
+
/**
|
|
7
|
+
* @alpha
|
|
8
|
+
*/
|
|
9
|
+
export const getSelectionText: EditorSelector<string> = ({context}) => {
|
|
17
10
|
let text = ''
|
|
18
11
|
|
|
12
|
+
const {value, selection} = context
|
|
13
|
+
|
|
19
14
|
if (!value || !selection) {
|
|
20
15
|
return text
|
|
21
16
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type {EditorSelector} from '../editor/editor-selector'
|
|
2
|
+
import {getStartPoint} from '../editor/utils/utils.get-start-point'
|
|
3
|
+
import {isKeyedSegment} from '../editor/utils/utils.is-keyed-segment'
|
|
4
|
+
import {reverseSelection} from '../editor/utils/utils.reverse-selection'
|
|
5
|
+
import {getSelectionText} from './selector.get-selection-text'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @alpha
|
|
9
|
+
*/
|
|
10
|
+
export const getBlockTextBefore: EditorSelector<string> = ({context}) => {
|
|
11
|
+
if (!context.selection) {
|
|
12
|
+
return ''
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const selection = context.selection.backward
|
|
16
|
+
? reverseSelection(context.selection)
|
|
17
|
+
: context.selection
|
|
18
|
+
const point = selection.anchor
|
|
19
|
+
const key = isKeyedSegment(point.path[0]) ? point.path[0]._key : undefined
|
|
20
|
+
|
|
21
|
+
const block = key
|
|
22
|
+
? context.value.find((block) => block._key === key)
|
|
23
|
+
: undefined
|
|
24
|
+
|
|
25
|
+
if (!block) {
|
|
26
|
+
return ''
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const startOfBlock = getStartPoint({node: block, path: [{_key: block._key}]})
|
|
30
|
+
|
|
31
|
+
return getSelectionText({
|
|
32
|
+
context: {
|
|
33
|
+
...context,
|
|
34
|
+
value: context.value,
|
|
35
|
+
selection: {
|
|
36
|
+
anchor: startOfBlock,
|
|
37
|
+
focus: point,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
}
|