@portabletext/editor 1.1.3 → 1.1.5
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 +228 -30
- package/lib/index.d.ts +228 -30
- package/lib/index.esm.js +169 -112
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +169 -112
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +169 -112
- package/lib/index.mjs.map +1 -1
- package/package.json +24 -19
- package/src/editor/Editable.tsx +6 -11
- package/src/editor/PortableTextEditor.tsx +26 -30
- package/src/editor/__tests__/self-solving.test.tsx +1 -1
- package/src/editor/components/SlateContainer.tsx +2 -13
- package/src/editor/components/Synchronizer.tsx +0 -3
- package/src/editor/editor-machine.ts +7 -2
- package/src/editor/hooks/useSyncValue.ts +3 -5
- package/src/editor/key-generator.ts +6 -0
- package/src/editor/plugins/createWithEditableAPI.ts +8 -5
- package/src/editor/plugins/createWithHotKeys.ts +1 -0
- package/src/editor/plugins/createWithInsertBreak.ts +57 -9
- package/src/editor/plugins/createWithInsertData.ts +7 -4
- package/src/editor/plugins/createWithObjectKeys.ts +12 -5
- package/src/editor/plugins/createWithPatches.ts +0 -1
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +106 -23
- package/src/editor/plugins/createWithSchemaTypes.ts +3 -4
- package/src/editor/plugins/createWithUtils.ts +5 -4
- package/src/editor/plugins/index.ts +5 -13
- package/src/index.ts +2 -2
- package/src/types/options.ts +0 -1
- package/src/utils/__tests__/operationToPatches.test.ts +0 -2
- package/src/utils/__tests__/patchToOperations.test.ts +1 -2
- package/src/editor/hooks/usePortableTextEditorKeyGenerator.ts +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"debug": "^4.3.4",
|
|
47
47
|
"is-hotkey-esm": "^1.0.0",
|
|
48
48
|
"lodash": "^4.17.21",
|
|
49
|
-
"slate": "0.
|
|
50
|
-
"slate-react": "0.110.
|
|
49
|
+
"slate": "0.110.2",
|
|
50
|
+
"slate-react": "0.110.2",
|
|
51
51
|
"xstate": "^5.18.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
@@ -55,28 +55,31 @@
|
|
|
55
55
|
"@babel/preset-react": "^7.24.7",
|
|
56
56
|
"@jest/globals": "^29.7.0",
|
|
57
57
|
"@jest/types": "^29.6.3",
|
|
58
|
-
"@playwright/test": "1.
|
|
58
|
+
"@playwright/test": "1.48.1",
|
|
59
59
|
"@portabletext/toolkit": "^2.0.15",
|
|
60
|
-
"@sanity/block-tools": "^3.
|
|
60
|
+
"@sanity/block-tools": "^3.61.0",
|
|
61
61
|
"@sanity/diff-match-patch": "^3.1.1",
|
|
62
62
|
"@sanity/pkg-utils": "^6.11.2",
|
|
63
|
-
"@sanity/schema": "^3.
|
|
64
|
-
"@sanity/types": "^3.
|
|
63
|
+
"@sanity/schema": "^3.61.0",
|
|
64
|
+
"@sanity/types": "^3.61.0",
|
|
65
65
|
"@sanity/ui": "^2.8.9",
|
|
66
|
-
"@sanity/util": "^3.
|
|
66
|
+
"@sanity/util": "^3.61.0",
|
|
67
67
|
"@testing-library/dom": "^10.4.0",
|
|
68
|
-
"@testing-library/jest-dom": "^6.
|
|
68
|
+
"@testing-library/jest-dom": "^6.6.2",
|
|
69
69
|
"@testing-library/react": "^16.0.1",
|
|
70
|
+
"@testing-library/user-event": "^14.5.2",
|
|
70
71
|
"@types/debug": "^4.1.5",
|
|
71
72
|
"@types/express": "^4.17.21",
|
|
72
73
|
"@types/express-ws": "^3.0.5",
|
|
73
74
|
"@types/lodash": "^4.17.7",
|
|
74
75
|
"@types/node": "^18.19.8",
|
|
75
76
|
"@types/node-ipc": "^9.2.3",
|
|
76
|
-
"@types/react": "^18.3.
|
|
77
|
-
"@types/react-dom": "^18.3.
|
|
77
|
+
"@types/react": "^18.3.11",
|
|
78
|
+
"@types/react-dom": "^18.3.1",
|
|
78
79
|
"@types/ws": "~8.5.12",
|
|
79
|
-
"@vitejs/plugin-react": "^4.3.
|
|
80
|
+
"@vitejs/plugin-react": "^4.3.3",
|
|
81
|
+
"@vitest/browser": "^2.1.3",
|
|
82
|
+
"@xstate/react": "^4.1.3",
|
|
80
83
|
"dotenv": "^16.4.5",
|
|
81
84
|
"express": "^4.19.2",
|
|
82
85
|
"express-ws": "^5.0.2",
|
|
@@ -85,21 +88,23 @@
|
|
|
85
88
|
"jest-environment-node": "^29.7.0",
|
|
86
89
|
"jsdom": "^25.0.1",
|
|
87
90
|
"node-ipc": "npm:@node-ipc/compat@9.2.5",
|
|
91
|
+
"playwright": "^1.48.1",
|
|
88
92
|
"react": "^18.3.1",
|
|
89
93
|
"react-dom": "^18.3.1",
|
|
90
94
|
"rxjs": "^7.8.1",
|
|
91
95
|
"styled-components": "^6.1.13",
|
|
92
96
|
"ts-node": "^10.9.2",
|
|
93
|
-
"typescript": "5.6.
|
|
94
|
-
"vite": "^5.4.
|
|
95
|
-
"vitest": "^2.1.
|
|
97
|
+
"typescript": "5.6.3",
|
|
98
|
+
"vite": "^5.4.9",
|
|
99
|
+
"vitest": "^2.1.3",
|
|
100
|
+
"vitest-browser-react": "^0.0.1",
|
|
96
101
|
"@sanity/gherkin-driver": "^0.0.1"
|
|
97
102
|
},
|
|
98
103
|
"peerDependencies": {
|
|
99
|
-
"@sanity/block-tools": "^3.
|
|
100
|
-
"@sanity/schema": "^3.
|
|
101
|
-
"@sanity/types": "^3.
|
|
102
|
-
"@sanity/util": "^3.
|
|
104
|
+
"@sanity/block-tools": "^3.61.0",
|
|
105
|
+
"@sanity/schema": "^3.61.0",
|
|
106
|
+
"@sanity/types": "^3.61.0",
|
|
107
|
+
"@sanity/util": "^3.61.0",
|
|
103
108
|
"react": "^16.9 || ^17 || ^18",
|
|
104
109
|
"rxjs": "^7.8.1",
|
|
105
110
|
"styled-components": "^6.1.13"
|
package/src/editor/Editable.tsx
CHANGED
|
@@ -11,8 +11,6 @@ import {
|
|
|
11
11
|
type ClipboardEvent,
|
|
12
12
|
type CSSProperties,
|
|
13
13
|
type FocusEventHandler,
|
|
14
|
-
type ForwardedRef,
|
|
15
|
-
type HTMLProps,
|
|
16
14
|
type KeyboardEvent,
|
|
17
15
|
type MutableRefObject,
|
|
18
16
|
type TextareaHTMLAttributes,
|
|
@@ -66,7 +64,6 @@ import {
|
|
|
66
64
|
import {Element} from './components/Element'
|
|
67
65
|
import {Leaf} from './components/Leaf'
|
|
68
66
|
import {usePortableTextEditor} from './hooks/usePortableTextEditor'
|
|
69
|
-
import {usePortableTextEditorKeyGenerator} from './hooks/usePortableTextEditorKeyGenerator'
|
|
70
67
|
import {usePortableTextEditorReadOnlyStatus} from './hooks/usePortableTextReadOnly'
|
|
71
68
|
import {createWithHotkeys, createWithInsertData} from './plugins'
|
|
72
69
|
import {PortableTextEditor} from './PortableTextEditor'
|
|
@@ -113,11 +110,10 @@ export type PortableTextEditableProps = Omit<
|
|
|
113
110
|
/**
|
|
114
111
|
* @public
|
|
115
112
|
*/
|
|
116
|
-
export const PortableTextEditable = forwardRef
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
) {
|
|
113
|
+
export const PortableTextEditable = forwardRef<
|
|
114
|
+
Omit<HTMLDivElement, 'as' | 'onPaste' | 'onBeforeInput'>,
|
|
115
|
+
PortableTextEditableProps
|
|
116
|
+
>(function PortableTextEditable(props, forwardedRef) {
|
|
121
117
|
const {
|
|
122
118
|
hotkeys,
|
|
123
119
|
onBlur,
|
|
@@ -142,7 +138,6 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
|
|
|
142
138
|
|
|
143
139
|
const portableTextEditor = usePortableTextEditor()
|
|
144
140
|
const readOnly = usePortableTextEditorReadOnlyStatus()
|
|
145
|
-
const keyGenerator = usePortableTextEditorKeyGenerator()
|
|
146
141
|
const ref = useRef<HTMLDivElement | null>(null)
|
|
147
142
|
const [editableElement, setEditableElement] = useState<HTMLDivElement | null>(
|
|
148
143
|
null,
|
|
@@ -167,8 +162,8 @@ export const PortableTextEditable = forwardRef(function PortableTextEditable(
|
|
|
167
162
|
|
|
168
163
|
// React/UI-specific plugins
|
|
169
164
|
const withInsertData = useMemo(
|
|
170
|
-
() => createWithInsertData(editorActor, schemaTypes
|
|
171
|
-
[editorActor,
|
|
165
|
+
() => createWithInsertData(editorActor, schemaTypes),
|
|
166
|
+
[editorActor, schemaTypes],
|
|
172
167
|
)
|
|
173
168
|
const withHotKeys = useMemo(
|
|
174
169
|
() => createWithHotkeys(schemaTypes, portableTextEditor, hotkeys),
|
|
@@ -28,12 +28,9 @@ import {SlateContainer} from './components/SlateContainer'
|
|
|
28
28
|
import {Synchronizer} from './components/Synchronizer'
|
|
29
29
|
import {editorMachine, type EditorActor} from './editor-machine'
|
|
30
30
|
import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
|
|
31
|
-
import {
|
|
32
|
-
defaultKeyGenerator,
|
|
33
|
-
PortableTextEditorKeyGeneratorContext,
|
|
34
|
-
} from './hooks/usePortableTextEditorKeyGenerator'
|
|
35
31
|
import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
|
|
36
32
|
import {PortableTextEditorReadOnlyContext} from './hooks/usePortableTextReadOnly'
|
|
33
|
+
import {defaultKeyGenerator} from './key-generator'
|
|
37
34
|
|
|
38
35
|
const debug = debugWithName('component:PortableTextEditor')
|
|
39
36
|
|
|
@@ -125,7 +122,11 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
|
|
|
125
122
|
)
|
|
126
123
|
}
|
|
127
124
|
|
|
128
|
-
this.editorActor = createActor(editorMachine
|
|
125
|
+
this.editorActor = createActor(editorMachine, {
|
|
126
|
+
input: {
|
|
127
|
+
keyGenerator: props.keyGenerator || defaultKeyGenerator,
|
|
128
|
+
},
|
|
129
|
+
})
|
|
129
130
|
this.editorActor.start()
|
|
130
131
|
|
|
131
132
|
this.schemaTypes = getPortableTextMemberSchemaTypes(
|
|
@@ -171,39 +172,34 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
|
|
|
171
172
|
: Number.parseInt(this.props.maxBlocks.toString(), 10) || undefined
|
|
172
173
|
|
|
173
174
|
const readOnly = Boolean(this.props.readOnly)
|
|
174
|
-
|
|
175
|
+
|
|
175
176
|
return (
|
|
176
177
|
<SlateContainer
|
|
177
|
-
keyGenerator={keyGenerator}
|
|
178
178
|
maxBlocks={maxBlocks}
|
|
179
179
|
patches$={_patches$}
|
|
180
180
|
portableTextEditor={this}
|
|
181
181
|
readOnly={readOnly}
|
|
182
182
|
>
|
|
183
|
-
<
|
|
184
|
-
<
|
|
185
|
-
<
|
|
186
|
-
<
|
|
183
|
+
<PortableTextEditorContext.Provider value={this}>
|
|
184
|
+
<PortableTextEditorReadOnlyContext.Provider value={readOnly}>
|
|
185
|
+
<PortableTextEditorSelectionProvider editorActor={this.editorActor}>
|
|
186
|
+
<Synchronizer
|
|
187
187
|
editorActor={this.editorActor}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
</PortableTextEditorSelectionProvider>
|
|
204
|
-
</PortableTextEditorReadOnlyContext.Provider>
|
|
205
|
-
</PortableTextEditorContext.Provider>
|
|
206
|
-
</PortableTextEditorKeyGeneratorContext.Provider>
|
|
188
|
+
getValue={this.getValue}
|
|
189
|
+
onChange={(change) => {
|
|
190
|
+
this.props.onChange(change)
|
|
191
|
+
/**
|
|
192
|
+
* For backwards compatibility, we relay all changes to the
|
|
193
|
+
* `change$` Subject as well.
|
|
194
|
+
*/
|
|
195
|
+
this.change$.next(change)
|
|
196
|
+
}}
|
|
197
|
+
value={value}
|
|
198
|
+
/>
|
|
199
|
+
{children}
|
|
200
|
+
</PortableTextEditorSelectionProvider>
|
|
201
|
+
</PortableTextEditorReadOnlyContext.Provider>
|
|
202
|
+
</PortableTextEditorContext.Provider>
|
|
207
203
|
</SlateContainer>
|
|
208
204
|
)
|
|
209
205
|
}
|
|
@@ -4,7 +4,7 @@ import type {PortableTextBlock, PortableTextSpan} from '@sanity/types'
|
|
|
4
4
|
import {render, waitFor} from '@testing-library/react'
|
|
5
5
|
import {createRef, type ComponentProps, type RefObject} from 'react'
|
|
6
6
|
import {describe, expect, it, vi} from 'vitest'
|
|
7
|
-
import {getTextSelection} from '../../../
|
|
7
|
+
import {getTextSelection} from '../../../gherkin-spec/gherkin-step-helpers'
|
|
8
8
|
import {PortableTextEditable} from '../Editable'
|
|
9
9
|
import {PortableTextEditor} from '../PortableTextEditor'
|
|
10
10
|
|
|
@@ -13,7 +13,6 @@ const debug = debugWithName('component:PortableTextEditor:SlateContainer')
|
|
|
13
13
|
* @internal
|
|
14
14
|
*/
|
|
15
15
|
export interface SlateContainerProps extends PropsWithChildren {
|
|
16
|
-
keyGenerator: () => string
|
|
17
16
|
maxBlocks: number | undefined
|
|
18
17
|
patches$?: PatchObservable
|
|
19
18
|
portableTextEditor: PortableTextEditor
|
|
@@ -25,14 +24,12 @@ export interface SlateContainerProps extends PropsWithChildren {
|
|
|
25
24
|
* @internal
|
|
26
25
|
*/
|
|
27
26
|
export function SlateContainer(props: SlateContainerProps) {
|
|
28
|
-
const {patches$, portableTextEditor, readOnly, maxBlocks
|
|
29
|
-
props
|
|
27
|
+
const {patches$, portableTextEditor, readOnly, maxBlocks} = props
|
|
30
28
|
|
|
31
29
|
// Create the slate instance, using `useState` ensures setup is only run once, initially
|
|
32
30
|
const [[slateEditor, subscribe]] = useState(() => {
|
|
33
31
|
debug('Creating new Slate editor instance')
|
|
34
32
|
const {editor, subscribe: _sub} = withPlugins(withReact(createEditor()), {
|
|
35
|
-
keyGenerator,
|
|
36
33
|
maxBlocks,
|
|
37
34
|
patches$,
|
|
38
35
|
portableTextEditor,
|
|
@@ -54,20 +51,12 @@ export function SlateContainer(props: SlateContainerProps) {
|
|
|
54
51
|
useEffect(() => {
|
|
55
52
|
debug('Re-initializing plugin chain')
|
|
56
53
|
withPlugins(slateEditor, {
|
|
57
|
-
keyGenerator,
|
|
58
54
|
maxBlocks,
|
|
59
55
|
patches$,
|
|
60
56
|
portableTextEditor,
|
|
61
57
|
readOnly,
|
|
62
58
|
})
|
|
63
|
-
}, [
|
|
64
|
-
keyGenerator,
|
|
65
|
-
portableTextEditor,
|
|
66
|
-
maxBlocks,
|
|
67
|
-
readOnly,
|
|
68
|
-
patches$,
|
|
69
|
-
slateEditor,
|
|
70
|
-
])
|
|
59
|
+
}, [portableTextEditor, maxBlocks, readOnly, patches$, slateEditor])
|
|
71
60
|
|
|
72
61
|
const initialValue = useMemo(() => {
|
|
73
62
|
return [slateEditor.pteCreateTextBlock({decorators: []})]
|
|
@@ -9,7 +9,6 @@ import {debugWithName} from '../../utils/debug'
|
|
|
9
9
|
import {IS_PROCESSING_LOCAL_CHANGES} from '../../utils/weakMaps'
|
|
10
10
|
import type {EditorActor} from '../editor-machine'
|
|
11
11
|
import {usePortableTextEditor} from '../hooks/usePortableTextEditor'
|
|
12
|
-
import {usePortableTextEditorKeyGenerator} from '../hooks/usePortableTextEditorKeyGenerator'
|
|
13
12
|
import {usePortableTextEditorReadOnlyStatus} from '../hooks/usePortableTextReadOnly'
|
|
14
13
|
import {useSyncValue} from '../hooks/useSyncValue'
|
|
15
14
|
|
|
@@ -36,14 +35,12 @@ export interface SynchronizerProps {
|
|
|
36
35
|
*/
|
|
37
36
|
export function Synchronizer(props: SynchronizerProps) {
|
|
38
37
|
const portableTextEditor = usePortableTextEditor()
|
|
39
|
-
const keyGenerator = usePortableTextEditorKeyGenerator()
|
|
40
38
|
const readOnly = usePortableTextEditorReadOnlyStatus()
|
|
41
39
|
const {editorActor, getValue, onChange, value} = props
|
|
42
40
|
const pendingPatches = useRef<Patch[]>([])
|
|
43
41
|
|
|
44
42
|
const syncValue = useSyncValue({
|
|
45
43
|
editorActor,
|
|
46
|
-
keyGenerator,
|
|
47
44
|
portableTextEditor,
|
|
48
45
|
readOnly,
|
|
49
46
|
})
|
|
@@ -90,10 +90,14 @@ type EditorEmittedEvent =
|
|
|
90
90
|
export const editorMachine = setup({
|
|
91
91
|
types: {
|
|
92
92
|
context: {} as {
|
|
93
|
+
keyGenerator: () => string
|
|
93
94
|
pendingEvents: Array<PatchEvent | MutationEvent>
|
|
94
95
|
},
|
|
95
96
|
events: {} as EditorEvent,
|
|
96
97
|
emitted: {} as EditorEmittedEvent,
|
|
98
|
+
input: {} as {
|
|
99
|
+
keyGenerator: () => string
|
|
100
|
+
},
|
|
97
101
|
},
|
|
98
102
|
actions: {
|
|
99
103
|
'emit patch event': emit(({event}) => {
|
|
@@ -124,9 +128,10 @@ export const editorMachine = setup({
|
|
|
124
128
|
},
|
|
125
129
|
}).createMachine({
|
|
126
130
|
id: 'editor',
|
|
127
|
-
context: {
|
|
131
|
+
context: ({input}) => ({
|
|
132
|
+
keyGenerator: input.keyGenerator,
|
|
128
133
|
pendingEvents: [],
|
|
129
|
-
},
|
|
134
|
+
}),
|
|
130
135
|
invoke: {
|
|
131
136
|
id: 'networkLogic',
|
|
132
137
|
src: 'networkLogic',
|
|
@@ -24,7 +24,6 @@ const debug = debugWithName('hook:useSyncValue')
|
|
|
24
24
|
*/
|
|
25
25
|
export interface UseSyncValueProps {
|
|
26
26
|
editorActor: EditorActor
|
|
27
|
-
keyGenerator: () => string
|
|
28
27
|
portableTextEditor: PortableTextEditor
|
|
29
28
|
readOnly: boolean
|
|
30
29
|
}
|
|
@@ -52,7 +51,7 @@ export function useSyncValue(
|
|
|
52
51
|
value: PortableTextBlock[] | undefined,
|
|
53
52
|
userCallbackFn?: () => void,
|
|
54
53
|
) => void {
|
|
55
|
-
const {editorActor, portableTextEditor, readOnly
|
|
54
|
+
const {editorActor, portableTextEditor, readOnly} = props
|
|
56
55
|
const {schemaTypes} = portableTextEditor
|
|
57
56
|
const previousValue = useRef<PortableTextBlock[] | undefined>()
|
|
58
57
|
const slateEditor = useSlate()
|
|
@@ -162,7 +161,7 @@ export function useSyncValue(
|
|
|
162
161
|
const validation = validateValue(
|
|
163
162
|
validationValue,
|
|
164
163
|
schemaTypes,
|
|
165
|
-
keyGenerator,
|
|
164
|
+
editorActor.getSnapshot().context.keyGenerator,
|
|
166
165
|
)
|
|
167
166
|
// Resolve validations that can be resolved automatically, without involving the user (but only if the value was changed)
|
|
168
167
|
if (
|
|
@@ -222,7 +221,7 @@ export function useSyncValue(
|
|
|
222
221
|
const validation = validateValue(
|
|
223
222
|
validationValue,
|
|
224
223
|
schemaTypes,
|
|
225
|
-
keyGenerator,
|
|
224
|
+
editorActor.getSnapshot().context.keyGenerator,
|
|
226
225
|
)
|
|
227
226
|
if (debug.enabled)
|
|
228
227
|
debug(
|
|
@@ -288,7 +287,6 @@ export function useSyncValue(
|
|
|
288
287
|
return updateFunction
|
|
289
288
|
}, [
|
|
290
289
|
editorActor,
|
|
291
|
-
keyGenerator,
|
|
292
290
|
portableTextEditor,
|
|
293
291
|
readOnly,
|
|
294
292
|
schemaTypes,
|
|
@@ -38,14 +38,15 @@ import {
|
|
|
38
38
|
KEY_TO_VALUE_ELEMENT,
|
|
39
39
|
SLATE_TO_PORTABLE_TEXT_RANGE,
|
|
40
40
|
} from '../../utils/weakMaps'
|
|
41
|
+
import type {EditorActor} from '../editor-machine'
|
|
41
42
|
import type {PortableTextEditor} from '../PortableTextEditor'
|
|
42
43
|
|
|
43
44
|
const debug = debugWithName('API:editable')
|
|
44
45
|
|
|
45
46
|
export function createWithEditableAPI(
|
|
47
|
+
editorActor: EditorActor,
|
|
46
48
|
portableTextEditor: PortableTextEditor,
|
|
47
49
|
types: PortableTextMemberSchemaTypes,
|
|
48
|
-
keyGenerator: () => string,
|
|
49
50
|
) {
|
|
50
51
|
return function withEditableAPI(
|
|
51
52
|
editor: PortableTextSlateEditor,
|
|
@@ -151,11 +152,11 @@ export function createWithEditableAPI(
|
|
|
151
152
|
const block = toSlateValue(
|
|
152
153
|
[
|
|
153
154
|
{
|
|
154
|
-
_key: keyGenerator(),
|
|
155
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
155
156
|
_type: types.block.name,
|
|
156
157
|
children: [
|
|
157
158
|
{
|
|
158
|
-
_key: keyGenerator(),
|
|
159
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
159
160
|
_type: type.name,
|
|
160
161
|
...(value ? value : {}),
|
|
161
162
|
},
|
|
@@ -199,7 +200,7 @@ export function createWithEditableAPI(
|
|
|
199
200
|
const block = toSlateValue(
|
|
200
201
|
[
|
|
201
202
|
{
|
|
202
|
-
_key: keyGenerator(),
|
|
203
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
203
204
|
_type: type.name,
|
|
204
205
|
...(value ? value : {}),
|
|
205
206
|
},
|
|
@@ -469,7 +470,9 @@ export function createWithEditableAPI(
|
|
|
469
470
|
continue
|
|
470
471
|
}
|
|
471
472
|
|
|
472
|
-
const annotationKey =
|
|
473
|
+
const annotationKey = editorActor
|
|
474
|
+
.getSnapshot()
|
|
475
|
+
.context.keyGenerator()
|
|
473
476
|
const markDefs = block.markDefs ?? []
|
|
474
477
|
const existingMarkDef = markDefs.find(
|
|
475
478
|
(markDef) =>
|
|
@@ -5,10 +5,11 @@ import type {
|
|
|
5
5
|
PortableTextSlateEditor,
|
|
6
6
|
} from '../../types/editor'
|
|
7
7
|
import type {SlateTextBlock, VoidElement} from '../../types/slate'
|
|
8
|
+
import type {EditorActor} from '../editor-machine'
|
|
8
9
|
|
|
9
10
|
export function createWithInsertBreak(
|
|
11
|
+
editorActor: EditorActor,
|
|
10
12
|
types: PortableTextMemberSchemaTypes,
|
|
11
|
-
keyGenerator: () => string,
|
|
12
13
|
): (editor: PortableTextSlateEditor) => PortableTextSlateEditor {
|
|
13
14
|
return function withInsertBreak(
|
|
14
15
|
editor: PortableTextSlateEditor,
|
|
@@ -21,6 +22,24 @@ export function createWithInsertBreak(
|
|
|
21
22
|
return
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
const [focusSpan] = Array.from(
|
|
26
|
+
Editor.nodes(editor, {
|
|
27
|
+
mode: 'lowest',
|
|
28
|
+
at: editor.selection.focus,
|
|
29
|
+
match: (n) => editor.isTextSpan(n),
|
|
30
|
+
voids: false,
|
|
31
|
+
}),
|
|
32
|
+
)[0] ?? [undefined]
|
|
33
|
+
const focusDecorators =
|
|
34
|
+
focusSpan.marks?.filter((mark) =>
|
|
35
|
+
types.decorators.some((decorator) => decorator.value === mark),
|
|
36
|
+
) ?? []
|
|
37
|
+
const focusAnnotations =
|
|
38
|
+
focusSpan.marks?.filter(
|
|
39
|
+
(mark) =>
|
|
40
|
+
!types.decorators.some((decorator) => decorator.value === mark),
|
|
41
|
+
) ?? []
|
|
42
|
+
|
|
24
43
|
const focusBlockPath = editor.selection.focus.path.slice(0, 1)
|
|
25
44
|
const focusBlock = Node.descendant(editor, focusBlockPath) as
|
|
26
45
|
| SlateTextBlock
|
|
@@ -34,15 +53,11 @@ export function createWithInsertBreak(
|
|
|
34
53
|
})
|
|
35
54
|
|
|
36
55
|
if (isEndAtStartOfBlock && Range.isCollapsed(editor.selection)) {
|
|
37
|
-
const focusDecorators = editor.isTextSpan(focusBlock.children[0])
|
|
38
|
-
? (focusBlock.children[0].marks ?? []).filter((mark) =>
|
|
39
|
-
types.decorators.some((decorator) => decorator.value === mark),
|
|
40
|
-
)
|
|
41
|
-
: []
|
|
42
|
-
|
|
43
56
|
Editor.insertNode(
|
|
44
57
|
editor,
|
|
45
|
-
editor.pteCreateTextBlock({
|
|
58
|
+
editor.pteCreateTextBlock({
|
|
59
|
+
decorators: focusAnnotations.length === 0 ? focusDecorators : [],
|
|
60
|
+
}),
|
|
46
61
|
)
|
|
47
62
|
|
|
48
63
|
const [nextBlockPath] = Path.next(focusBlockPath)
|
|
@@ -64,6 +79,36 @@ export function createWithInsertBreak(
|
|
|
64
79
|
? lastFocusBlockChild.text.length
|
|
65
80
|
: 0,
|
|
66
81
|
})
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
isStartAtEndOfBlock &&
|
|
85
|
+
Range.isCollapsed(editor.selection) &&
|
|
86
|
+
focusDecorators.length > 0 &&
|
|
87
|
+
focusAnnotations.length > 0
|
|
88
|
+
) {
|
|
89
|
+
Editor.withoutNormalizing(editor, () => {
|
|
90
|
+
if (!editor.selection) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Editor.insertNode(
|
|
95
|
+
editor,
|
|
96
|
+
editor.pteCreateTextBlock({
|
|
97
|
+
decorators: [],
|
|
98
|
+
}),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
const [nextBlockPath] = Path.next(focusBlockPath)
|
|
102
|
+
|
|
103
|
+
Transforms.setSelection(editor, {
|
|
104
|
+
anchor: {path: [nextBlockPath, 0], offset: 0},
|
|
105
|
+
focus: {path: [nextBlockPath, 0], offset: 0},
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
editor.onChange()
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
67
112
|
const isInTheMiddleOfNode = !isEndAtStartOfBlock && !isStartAtEndOfBlock
|
|
68
113
|
|
|
69
114
|
if (isInTheMiddleOfNode) {
|
|
@@ -131,7 +176,10 @@ export function createWithInsertBreak(
|
|
|
131
176
|
) {
|
|
132
177
|
// This annotation is both present in the previous block
|
|
133
178
|
// and this block, so let's assign a new key to it
|
|
134
|
-
newMarkDefKeys.set(
|
|
179
|
+
newMarkDefKeys.set(
|
|
180
|
+
mark,
|
|
181
|
+
editorActor.getSnapshot().context.keyGenerator(),
|
|
182
|
+
)
|
|
135
183
|
}
|
|
136
184
|
}
|
|
137
185
|
|
|
@@ -25,7 +25,6 @@ const debug = debugWithName('plugin:withInsertData')
|
|
|
25
25
|
export function createWithInsertData(
|
|
26
26
|
editorActor: EditorActor,
|
|
27
27
|
schemaTypes: PortableTextMemberSchemaTypes,
|
|
28
|
-
keyGenerator: () => string,
|
|
29
28
|
) {
|
|
30
29
|
return function withInsertData(
|
|
31
30
|
editor: PortableTextSlateEditor,
|
|
@@ -149,12 +148,16 @@ export function createWithInsertData(
|
|
|
149
148
|
const slateValue = _regenerateKeys(
|
|
150
149
|
editor,
|
|
151
150
|
toSlateValue(parsed, {schemaTypes}),
|
|
152
|
-
keyGenerator,
|
|
151
|
+
editorActor.getSnapshot().context.keyGenerator,
|
|
153
152
|
spanTypeName,
|
|
154
153
|
schemaTypes,
|
|
155
154
|
)
|
|
156
155
|
// Validate the result
|
|
157
|
-
const validation = validateValue(
|
|
156
|
+
const validation = validateValue(
|
|
157
|
+
parsed,
|
|
158
|
+
schemaTypes,
|
|
159
|
+
editorActor.getSnapshot().context.keyGenerator,
|
|
160
|
+
)
|
|
158
161
|
// Bail out if it's not valid
|
|
159
162
|
if (!validation.valid && !validation.resolution?.autoResolve) {
|
|
160
163
|
const errorDescription = `${validation.resolution?.description}`
|
|
@@ -224,7 +227,7 @@ export function createWithInsertData(
|
|
|
224
227
|
const validation = validateValue(
|
|
225
228
|
portableText,
|
|
226
229
|
schemaTypes,
|
|
227
|
-
keyGenerator,
|
|
230
|
+
editorActor.getSnapshot().context.keyGenerator,
|
|
228
231
|
)
|
|
229
232
|
|
|
230
233
|
// Bail out if it's not valid
|
|
@@ -14,7 +14,6 @@ import type {EditorActor} from '../editor-machine'
|
|
|
14
14
|
export function createWithObjectKeys(
|
|
15
15
|
editorActor: EditorActor,
|
|
16
16
|
schemaTypes: PortableTextMemberSchemaTypes,
|
|
17
|
-
keyGenerator: () => string,
|
|
18
17
|
) {
|
|
19
18
|
return function withKeys(
|
|
20
19
|
editor: PortableTextSlateEditor,
|
|
@@ -48,7 +47,7 @@ export function createWithObjectKeys(
|
|
|
48
47
|
...operation,
|
|
49
48
|
properties: {
|
|
50
49
|
...operation.properties,
|
|
51
|
-
_key: keyGenerator(),
|
|
50
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
52
51
|
},
|
|
53
52
|
})
|
|
54
53
|
|
|
@@ -61,7 +60,7 @@ export function createWithObjectKeys(
|
|
|
61
60
|
...operation,
|
|
62
61
|
node: {
|
|
63
62
|
...operation.node,
|
|
64
|
-
_key: keyGenerator(),
|
|
63
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
65
64
|
},
|
|
66
65
|
})
|
|
67
66
|
|
|
@@ -78,7 +77,11 @@ export function createWithObjectKeys(
|
|
|
78
77
|
// Set key on block itself
|
|
79
78
|
if (!node._key) {
|
|
80
79
|
editorActor.send({type: 'normalizing'})
|
|
81
|
-
Transforms.setNodes(
|
|
80
|
+
Transforms.setNodes(
|
|
81
|
+
editor,
|
|
82
|
+
{_key: editorActor.getSnapshot().context.keyGenerator()},
|
|
83
|
+
{at: path},
|
|
84
|
+
)
|
|
82
85
|
editorActor.send({type: 'done normalizing'})
|
|
83
86
|
return
|
|
84
87
|
}
|
|
@@ -86,7 +89,11 @@ export function createWithObjectKeys(
|
|
|
86
89
|
for (const [child, childPath] of Node.children(editor, path)) {
|
|
87
90
|
if (!child._key) {
|
|
88
91
|
editorActor.send({type: 'normalizing'})
|
|
89
|
-
Transforms.setNodes(
|
|
92
|
+
Transforms.setNodes(
|
|
93
|
+
editor,
|
|
94
|
+
{_key: editorActor.getSnapshot().context.keyGenerator()},
|
|
95
|
+
{at: childPath},
|
|
96
|
+
)
|
|
90
97
|
editorActor.send({type: 'done normalizing'})
|
|
91
98
|
return
|
|
92
99
|
}
|