@prosekit/core 0.8.2 → 0.8.4
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/dist/editor-CfkZ4TNU.d.ts +748 -0
- package/dist/editor-CfkZ4TNU.d.ts.map +1 -0
- package/dist/{editor-DbMrpnmL.js → editor-CizSwUN8.js} +102 -192
- package/dist/editor-CizSwUN8.js.map +1 -0
- package/dist/prosekit-core-test.d.ts +20 -19
- package/dist/prosekit-core-test.d.ts.map +1 -0
- package/dist/prosekit-core-test.js +4 -5
- package/dist/prosekit-core-test.js.map +1 -0
- package/dist/prosekit-core.d.ts +782 -757
- package/dist/prosekit-core.d.ts.map +1 -0
- package/dist/prosekit-core.js +30 -45
- package/dist/prosekit-core.js.map +1 -0
- package/package.json +14 -11
- package/src/commands/add-mark.ts +53 -0
- package/src/commands/expand-mark.ts +96 -0
- package/src/commands/insert-default-block.spec.ts +102 -0
- package/src/commands/insert-default-block.ts +49 -0
- package/src/commands/insert-node.ts +71 -0
- package/src/commands/insert-text.ts +24 -0
- package/src/commands/remove-mark.ts +54 -0
- package/src/commands/remove-node.ts +43 -0
- package/src/commands/select-all.ts +16 -0
- package/src/commands/set-block-type.ts +64 -0
- package/src/commands/set-node-attrs.ts +68 -0
- package/src/commands/toggle-mark.ts +65 -0
- package/src/commands/toggle-node.ts +47 -0
- package/src/commands/toggle-wrap.spec.ts +35 -0
- package/src/commands/toggle-wrap.ts +42 -0
- package/src/commands/unset-block-type.spec.ts +49 -0
- package/src/commands/unset-block-type.ts +84 -0
- package/src/commands/unset-mark.spec.ts +35 -0
- package/src/commands/unset-mark.ts +38 -0
- package/src/commands/wrap.ts +50 -0
- package/src/editor/action.spec.ts +143 -0
- package/src/editor/action.ts +248 -0
- package/src/editor/editor.spec.ts +186 -0
- package/src/editor/editor.ts +563 -0
- package/src/editor/union.spec.ts +108 -0
- package/src/editor/union.ts +47 -0
- package/src/editor/with-priority.ts +25 -0
- package/src/error.ts +28 -0
- package/src/extensions/clipboard-serializer.ts +107 -0
- package/src/extensions/command.ts +121 -0
- package/src/extensions/default-state.spec.ts +60 -0
- package/src/extensions/default-state.ts +76 -0
- package/src/extensions/doc.ts +31 -0
- package/src/extensions/events/doc-change.ts +34 -0
- package/src/extensions/events/dom-event.spec.ts +70 -0
- package/src/extensions/events/dom-event.ts +117 -0
- package/src/extensions/events/editor-event.ts +293 -0
- package/src/extensions/events/focus.spec.ts +50 -0
- package/src/extensions/events/focus.ts +28 -0
- package/src/extensions/events/plugin-view.ts +132 -0
- package/src/extensions/history.ts +81 -0
- package/src/extensions/keymap-base.ts +60 -0
- package/src/extensions/keymap.spec.ts +89 -0
- package/src/extensions/keymap.ts +96 -0
- package/src/extensions/mark-spec.spec.ts +177 -0
- package/src/extensions/mark-spec.ts +181 -0
- package/src/extensions/mark-view-effect.ts +85 -0
- package/src/extensions/mark-view.ts +43 -0
- package/src/extensions/node-spec.spec.ts +224 -0
- package/src/extensions/node-spec.ts +199 -0
- package/src/extensions/node-view-effect.ts +85 -0
- package/src/extensions/node-view.ts +43 -0
- package/src/extensions/paragraph.ts +61 -0
- package/src/extensions/plugin.ts +91 -0
- package/src/extensions/text.ts +34 -0
- package/src/facets/base-extension.ts +54 -0
- package/src/facets/command.ts +21 -0
- package/src/facets/facet-extension.spec.ts +173 -0
- package/src/facets/facet-extension.ts +53 -0
- package/src/facets/facet-node.spec.ts +265 -0
- package/src/facets/facet-node.ts +185 -0
- package/src/facets/facet-types.ts +9 -0
- package/src/facets/facet.spec.ts +76 -0
- package/src/facets/facet.ts +84 -0
- package/src/facets/root.ts +44 -0
- package/src/facets/schema-spec.ts +30 -0
- package/src/facets/schema.ts +26 -0
- package/src/facets/state.ts +57 -0
- package/src/facets/union-extension.ts +41 -0
- package/src/index.ts +302 -0
- package/src/test/index.ts +4 -0
- package/src/test/test-builder.ts +68 -0
- package/src/test/test-editor.spec.ts +104 -0
- package/src/test/test-editor.ts +113 -0
- package/src/testing/index.ts +283 -0
- package/src/testing/keyboard.ts +5 -0
- package/src/types/any-function.ts +4 -0
- package/src/types/assert-type-equal.ts +8 -0
- package/src/types/attrs.ts +32 -0
- package/src/types/base-node-view-options.ts +33 -0
- package/src/types/dom-node.ts +1 -0
- package/src/types/extension-command.ts +52 -0
- package/src/types/extension-mark.ts +15 -0
- package/src/types/extension-node.ts +15 -0
- package/src/types/extension.spec.ts +56 -0
- package/src/types/extension.ts +168 -0
- package/src/types/model.ts +54 -0
- package/src/types/object-entries.ts +13 -0
- package/src/types/pick-string-literal.spec.ts +10 -0
- package/src/types/pick-string-literal.ts +6 -0
- package/src/types/pick-sub-type.spec.ts +20 -0
- package/src/types/pick-sub-type.ts +6 -0
- package/src/types/priority.ts +12 -0
- package/src/types/setter.ts +4 -0
- package/src/types/simplify-deeper.spec.ts +40 -0
- package/src/types/simplify-deeper.ts +6 -0
- package/src/types/simplify-union.spec.ts +21 -0
- package/src/types/simplify-union.ts +11 -0
- package/src/utils/array-grouping.spec.ts +29 -0
- package/src/utils/array-grouping.ts +25 -0
- package/src/utils/array.ts +21 -0
- package/src/utils/assert.ts +13 -0
- package/src/utils/attrs-match.ts +20 -0
- package/src/utils/can-use-regex-lookbehind.ts +12 -0
- package/src/utils/clsx.spec.ts +14 -0
- package/src/utils/clsx.ts +12 -0
- package/src/utils/collect-children.ts +21 -0
- package/src/utils/collect-nodes.ts +37 -0
- package/src/utils/combine-event-handlers.spec.ts +27 -0
- package/src/utils/combine-event-handlers.ts +27 -0
- package/src/utils/contains-inline-node.ts +17 -0
- package/src/utils/deep-equals.spec.ts +26 -0
- package/src/utils/deep-equals.ts +29 -0
- package/src/utils/default-block-at.ts +15 -0
- package/src/utils/editor-content.spec.ts +47 -0
- package/src/utils/editor-content.ts +77 -0
- package/src/utils/env.ts +6 -0
- package/src/utils/find-parent-node-of-type.ts +29 -0
- package/src/utils/find-parent-node.spec.ts +68 -0
- package/src/utils/find-parent-node.ts +55 -0
- package/src/utils/get-custom-selection.ts +19 -0
- package/src/utils/get-dom-api.ts +56 -0
- package/src/utils/get-id.spec.ts +14 -0
- package/src/utils/get-id.ts +13 -0
- package/src/utils/get-mark-type.ts +20 -0
- package/src/utils/get-node-type.ts +20 -0
- package/src/utils/get-node-types.ts +19 -0
- package/src/utils/includes-mark.ts +18 -0
- package/src/utils/is-at-block-start.ts +26 -0
- package/src/utils/is-in-code-block.ts +18 -0
- package/src/utils/is-mark-absent.spec.ts +53 -0
- package/src/utils/is-mark-absent.ts +42 -0
- package/src/utils/is-mark-active.ts +27 -0
- package/src/utils/is-node-active.ts +25 -0
- package/src/utils/is-subset.spec.ts +12 -0
- package/src/utils/is-subset.ts +11 -0
- package/src/utils/maybe-run.spec.ts +39 -0
- package/src/utils/maybe-run.ts +11 -0
- package/src/utils/merge-objects.spec.ts +30 -0
- package/src/utils/merge-objects.ts +11 -0
- package/src/utils/merge-specs.ts +35 -0
- package/src/utils/object-equal.spec.ts +26 -0
- package/src/utils/object-equal.ts +28 -0
- package/src/utils/output-spec.test.ts +95 -0
- package/src/utils/output-spec.ts +130 -0
- package/src/utils/parse.spec.ts +46 -0
- package/src/utils/parse.ts +321 -0
- package/src/utils/remove-undefined-values.spec.ts +15 -0
- package/src/utils/remove-undefined-values.ts +9 -0
- package/src/utils/set-selection-around.ts +11 -0
- package/src/utils/type-assertion.ts +91 -0
- package/src/utils/unicode.spec.ts +10 -0
- package/src/utils/unicode.ts +4 -0
- package/src/utils/with-skip-code-block.ts +15 -0
- package/dist/editor-CjVyjJqw.d.ts +0 -739
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Node,
|
|
3
|
+
Slice,
|
|
4
|
+
} from '@prosekit/pm/model'
|
|
5
|
+
import {
|
|
6
|
+
PluginKey,
|
|
7
|
+
ProseMirrorPlugin,
|
|
8
|
+
} from '@prosekit/pm/state'
|
|
9
|
+
import type { EditorView } from '@prosekit/pm/view'
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
defineFacet,
|
|
13
|
+
type Facet,
|
|
14
|
+
} from '../../facets/facet'
|
|
15
|
+
import { defineFacetPayload } from '../../facets/facet-extension'
|
|
16
|
+
import type { PlainExtension } from '../../types/extension'
|
|
17
|
+
import type { ObjectEntries } from '../../types/object-entries'
|
|
18
|
+
import { groupEntries } from '../../utils/array-grouping'
|
|
19
|
+
import { combineEventHandlers } from '../../utils/combine-event-handlers'
|
|
20
|
+
import {
|
|
21
|
+
pluginFacet,
|
|
22
|
+
type PluginPayload,
|
|
23
|
+
} from '../plugin'
|
|
24
|
+
|
|
25
|
+
export type KeyDownHandler = (
|
|
26
|
+
view: EditorView,
|
|
27
|
+
event: KeyboardEvent,
|
|
28
|
+
) => boolean | void
|
|
29
|
+
export type KeyPressHandler = (
|
|
30
|
+
view: EditorView,
|
|
31
|
+
event: KeyboardEvent,
|
|
32
|
+
) => boolean | void
|
|
33
|
+
export type TextInputHandler = (
|
|
34
|
+
view: EditorView,
|
|
35
|
+
from: number,
|
|
36
|
+
to: number,
|
|
37
|
+
text: string,
|
|
38
|
+
) => boolean | void
|
|
39
|
+
export type ClickOnHandler = (
|
|
40
|
+
view: EditorView,
|
|
41
|
+
pos: number,
|
|
42
|
+
node: Node,
|
|
43
|
+
nodePos: number,
|
|
44
|
+
event: MouseEvent,
|
|
45
|
+
direct: boolean,
|
|
46
|
+
) => boolean | void
|
|
47
|
+
export type ClickHandler = (
|
|
48
|
+
view: EditorView,
|
|
49
|
+
pos: number,
|
|
50
|
+
event: MouseEvent,
|
|
51
|
+
) => boolean | void
|
|
52
|
+
export type DoubleClickOnHandler = (
|
|
53
|
+
view: EditorView,
|
|
54
|
+
pos: number,
|
|
55
|
+
node: Node,
|
|
56
|
+
nodePos: number,
|
|
57
|
+
event: MouseEvent,
|
|
58
|
+
direct: boolean,
|
|
59
|
+
) => boolean | void
|
|
60
|
+
export type DoubleClickHandler = (
|
|
61
|
+
view: EditorView,
|
|
62
|
+
pos: number,
|
|
63
|
+
event: MouseEvent,
|
|
64
|
+
) => boolean | void
|
|
65
|
+
export type TripleClickOnHandler = (
|
|
66
|
+
view: EditorView,
|
|
67
|
+
pos: number,
|
|
68
|
+
node: Node,
|
|
69
|
+
nodePos: number,
|
|
70
|
+
event: MouseEvent,
|
|
71
|
+
direct: boolean,
|
|
72
|
+
) => boolean | void
|
|
73
|
+
export type TripleClickHandler = (
|
|
74
|
+
view: EditorView,
|
|
75
|
+
pos: number,
|
|
76
|
+
event: MouseEvent,
|
|
77
|
+
) => boolean | void
|
|
78
|
+
export type PasteHandler = (
|
|
79
|
+
view: EditorView,
|
|
80
|
+
event: ClipboardEvent,
|
|
81
|
+
slice: Slice,
|
|
82
|
+
) => boolean | void
|
|
83
|
+
export type DropHandler = (
|
|
84
|
+
view: EditorView,
|
|
85
|
+
event: DragEvent,
|
|
86
|
+
slice: Slice,
|
|
87
|
+
moved: boolean,
|
|
88
|
+
) => boolean | void
|
|
89
|
+
export type ScrollToSelectionHandler = (view: EditorView) => boolean
|
|
90
|
+
|
|
91
|
+
function defineEventFacetPayload(payload: EditorEventPayload): PlainExtension {
|
|
92
|
+
return defineFacetPayload(editorEventFacet, [payload]) as PlainExtension
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @public
|
|
97
|
+
*
|
|
98
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleKeyDown}
|
|
99
|
+
*/
|
|
100
|
+
export function defineKeyDownHandler(handler: KeyDownHandler): PlainExtension {
|
|
101
|
+
return defineEventFacetPayload(['keyDown', handler])
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @public
|
|
105
|
+
*
|
|
106
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleKeyPress}
|
|
107
|
+
*/
|
|
108
|
+
export function defineKeyPressHandler(
|
|
109
|
+
handler: KeyPressHandler,
|
|
110
|
+
): PlainExtension {
|
|
111
|
+
return defineEventFacetPayload(['keyPress', handler])
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* @public
|
|
115
|
+
*
|
|
116
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleTextInput}
|
|
117
|
+
*/
|
|
118
|
+
export function defineTextInputHandler(
|
|
119
|
+
handler: TextInputHandler,
|
|
120
|
+
): PlainExtension {
|
|
121
|
+
return defineEventFacetPayload(['textInput', handler])
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* @public
|
|
125
|
+
*
|
|
126
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleClickOn}
|
|
127
|
+
*/
|
|
128
|
+
export function defineClickOnHandler(handler: ClickOnHandler): PlainExtension {
|
|
129
|
+
return defineEventFacetPayload(['clickOn', handler])
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* @public
|
|
133
|
+
*
|
|
134
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleClick}
|
|
135
|
+
*/
|
|
136
|
+
export function defineClickHandler(handler: ClickHandler): PlainExtension {
|
|
137
|
+
return defineEventFacetPayload(['click', handler])
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* @public
|
|
141
|
+
*
|
|
142
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleDoubleClickOn}
|
|
143
|
+
*/
|
|
144
|
+
export function defineDoubleClickOnHandler(
|
|
145
|
+
handler: DoubleClickOnHandler,
|
|
146
|
+
): PlainExtension {
|
|
147
|
+
return defineEventFacetPayload(['doubleClickOn', handler])
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* @public
|
|
151
|
+
*
|
|
152
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleDoubleClick}
|
|
153
|
+
*/
|
|
154
|
+
export function defineDoubleClickHandler(
|
|
155
|
+
handler: DoubleClickHandler,
|
|
156
|
+
): PlainExtension {
|
|
157
|
+
return defineEventFacetPayload(['doubleClick', handler])
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* @public
|
|
161
|
+
*
|
|
162
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleTripleClickOn}
|
|
163
|
+
*/
|
|
164
|
+
export function defineTripleClickOnHandler(
|
|
165
|
+
handler: TripleClickOnHandler,
|
|
166
|
+
): PlainExtension {
|
|
167
|
+
return defineEventFacetPayload(['tripleClickOn', handler])
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* @public
|
|
171
|
+
*
|
|
172
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleTripleClick}
|
|
173
|
+
*/
|
|
174
|
+
export function defineTripleClickHandler(
|
|
175
|
+
handler: TripleClickHandler,
|
|
176
|
+
): PlainExtension {
|
|
177
|
+
return defineEventFacetPayload(['tripleClick', handler])
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @public
|
|
181
|
+
*
|
|
182
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste}
|
|
183
|
+
*/
|
|
184
|
+
export function definePasteHandler(handler: PasteHandler): PlainExtension {
|
|
185
|
+
return defineEventFacetPayload(['paste', handler])
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* @public
|
|
189
|
+
*
|
|
190
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleDrop}
|
|
191
|
+
*/
|
|
192
|
+
export function defineDropHandler(handler: DropHandler): PlainExtension {
|
|
193
|
+
return defineEventFacetPayload(['drop', handler])
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* @public
|
|
197
|
+
*
|
|
198
|
+
* See {@link https://prosemirror.net/docs/ref/#view.EditorProps.handleScrollToSelection}
|
|
199
|
+
*/
|
|
200
|
+
export function defineScrollToSelectionHandler(
|
|
201
|
+
handler: ScrollToSelectionHandler,
|
|
202
|
+
): PlainExtension {
|
|
203
|
+
return defineEventFacetPayload(['scrollToSelection', handler])
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface EditorEventMap {
|
|
207
|
+
keyDown: KeyDownHandler
|
|
208
|
+
keyPress: KeyPressHandler
|
|
209
|
+
textInput: TextInputHandler
|
|
210
|
+
clickOn: ClickOnHandler
|
|
211
|
+
click: ClickHandler
|
|
212
|
+
doubleClickOn: DoubleClickOnHandler
|
|
213
|
+
doubleClick: DoubleClickHandler
|
|
214
|
+
tripleClickOn: TripleClickOnHandler
|
|
215
|
+
tripleClick: TripleClickHandler
|
|
216
|
+
paste: PasteHandler
|
|
217
|
+
drop: DropHandler
|
|
218
|
+
scrollToSelection: ScrollToSelectionHandler
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @internal
|
|
223
|
+
*/
|
|
224
|
+
export type EditorEventPayload = ObjectEntries<EditorEventMap>
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @internal
|
|
228
|
+
*/
|
|
229
|
+
export const editorEventFacet: Facet<EditorEventPayload, PluginPayload> = defineFacet<EditorEventPayload, PluginPayload>({
|
|
230
|
+
reduce: () => {
|
|
231
|
+
const [update, plugin] = setupEditorEventPlugin()
|
|
232
|
+
|
|
233
|
+
return (entries) => {
|
|
234
|
+
update(entries)
|
|
235
|
+
return plugin
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
parent: pluginFacet,
|
|
239
|
+
singleton: true,
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
// dprint-ignore
|
|
243
|
+
function setupEditorEventPlugin() {
|
|
244
|
+
const [setKeyDownHandlers, handleKeyDown] = combineEventHandlers<KeyDownHandler>()
|
|
245
|
+
const [setKeyPressHandlers, handleKeyPress] = combineEventHandlers<KeyPressHandler>()
|
|
246
|
+
const [setTextInputHandlers, handleTextInput] = combineEventHandlers<TextInputHandler>()
|
|
247
|
+
const [setClickOnHandlers, handleClickOn] = combineEventHandlers<ClickOnHandler>()
|
|
248
|
+
const [setClickHandlers, handleClick] = combineEventHandlers<ClickHandler>()
|
|
249
|
+
const [setDoubleClickOnHandlers, handleDoubleClickOn] = combineEventHandlers<DoubleClickOnHandler>()
|
|
250
|
+
const [setDoubleClickHandlers, handleDoubleClick] = combineEventHandlers<DoubleClickHandler>()
|
|
251
|
+
const [setTripleClickOnHandlers, handleTripleClickOn] = combineEventHandlers<TripleClickOnHandler>()
|
|
252
|
+
const [setTripleClickHandlers, handleTripleClick] = combineEventHandlers<TripleClickHandler>()
|
|
253
|
+
const [setPasteHandlers, handlePaste] = combineEventHandlers<PasteHandler>()
|
|
254
|
+
const [setDropHandlers, handleDrop] = combineEventHandlers<DropHandler>()
|
|
255
|
+
const [setScrollToSelectionHandlers, handleScrollToSelection] = combineEventHandlers<ScrollToSelectionHandler>()
|
|
256
|
+
|
|
257
|
+
const update = (entries: EditorEventPayload[]) => {
|
|
258
|
+
const map = groupEntries<EditorEventMap>(entries)
|
|
259
|
+
|
|
260
|
+
setKeyDownHandlers(map.keyDown ?? [])
|
|
261
|
+
setKeyPressHandlers(map.keyPress ?? [])
|
|
262
|
+
setTextInputHandlers(map.textInput ?? [])
|
|
263
|
+
setClickOnHandlers(map.clickOn ?? [])
|
|
264
|
+
setClickHandlers(map.click ?? [])
|
|
265
|
+
setDoubleClickOnHandlers(map.doubleClickOn ?? [])
|
|
266
|
+
setDoubleClickHandlers(map.doubleClick ?? [])
|
|
267
|
+
setTripleClickOnHandlers(map.tripleClickOn ?? [])
|
|
268
|
+
setTripleClickHandlers(map.tripleClick ?? [])
|
|
269
|
+
setPasteHandlers(map.paste ?? [])
|
|
270
|
+
setDropHandlers(map.drop ?? [])
|
|
271
|
+
setScrollToSelectionHandlers(map.scrollToSelection ?? [])
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const plugin = new ProseMirrorPlugin({
|
|
275
|
+
key: new PluginKey('prosekit-editor-event'),
|
|
276
|
+
props: {
|
|
277
|
+
handleKeyDown,
|
|
278
|
+
handleKeyPress,
|
|
279
|
+
handleTextInput,
|
|
280
|
+
handleClickOn,
|
|
281
|
+
handleClick,
|
|
282
|
+
handleDoubleClickOn,
|
|
283
|
+
handleDoubleClick,
|
|
284
|
+
handleTripleClickOn,
|
|
285
|
+
handleTripleClick,
|
|
286
|
+
handlePaste,
|
|
287
|
+
handleDrop,
|
|
288
|
+
handleScrollToSelection,
|
|
289
|
+
},
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
return [update, plugin] as const
|
|
293
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
vi,
|
|
6
|
+
} from 'vitest'
|
|
7
|
+
|
|
8
|
+
import { createEditor } from '../../editor/editor'
|
|
9
|
+
import { union } from '../../editor/union'
|
|
10
|
+
import { defineTestExtension } from '../../testing'
|
|
11
|
+
|
|
12
|
+
import { defineFocusChangeHandler } from './focus'
|
|
13
|
+
|
|
14
|
+
describe('defineFocusChangeHandler', () => {
|
|
15
|
+
it('should call the handler when the editor is focused or blurred', () => {
|
|
16
|
+
const div = document.body.appendChild(document.createElement('div'))
|
|
17
|
+
const handleFocusChange = vi.fn()
|
|
18
|
+
|
|
19
|
+
const extension = union(
|
|
20
|
+
defineTestExtension(),
|
|
21
|
+
defineFocusChangeHandler(handleFocusChange),
|
|
22
|
+
)
|
|
23
|
+
const editor = createEditor({ extension })
|
|
24
|
+
editor.mount(div)
|
|
25
|
+
|
|
26
|
+
expect(handleFocusChange).toHaveBeenCalledTimes(0)
|
|
27
|
+
|
|
28
|
+
editor.focus()
|
|
29
|
+
expect(handleFocusChange).toHaveBeenCalledTimes(1)
|
|
30
|
+
expect(handleFocusChange).toHaveBeenLastCalledWith(true)
|
|
31
|
+
|
|
32
|
+
editor.blur()
|
|
33
|
+
expect(handleFocusChange).toHaveBeenCalledTimes(2)
|
|
34
|
+
expect(handleFocusChange).toHaveBeenLastCalledWith(false)
|
|
35
|
+
|
|
36
|
+
editor.focus()
|
|
37
|
+
editor.focus()
|
|
38
|
+
editor.focus()
|
|
39
|
+
editor.focus()
|
|
40
|
+
expect(handleFocusChange).toHaveBeenCalledTimes(3)
|
|
41
|
+
expect(handleFocusChange).toHaveBeenLastCalledWith(true)
|
|
42
|
+
|
|
43
|
+
editor.blur()
|
|
44
|
+
editor.blur()
|
|
45
|
+
editor.blur()
|
|
46
|
+
editor.blur()
|
|
47
|
+
expect(handleFocusChange).toHaveBeenCalledTimes(4)
|
|
48
|
+
expect(handleFocusChange).toHaveBeenLastCalledWith(false)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PlainExtension } from '../../types/extension'
|
|
2
|
+
|
|
3
|
+
import { defineDomEventFacetPayload } from './dom-event'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A function that is called when the editor gains or loses focus.
|
|
7
|
+
*
|
|
8
|
+
* @param hasFocus - Whether the editor has focus.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export type FocusChangeHandler = (hasFocus: boolean) => void
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Registers a event handler that is called when the editor gains or loses focus.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export function defineFocusChangeHandler(
|
|
20
|
+
handler: FocusChangeHandler,
|
|
21
|
+
): PlainExtension {
|
|
22
|
+
const handleFocus = () => handler(true)
|
|
23
|
+
const handleBlur = () => handler(false)
|
|
24
|
+
return defineDomEventFacetPayload(
|
|
25
|
+
['focus', handleFocus],
|
|
26
|
+
['blur', handleBlur],
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PluginKey,
|
|
3
|
+
ProseMirrorPlugin,
|
|
4
|
+
type EditorState,
|
|
5
|
+
} from '@prosekit/pm/state'
|
|
6
|
+
import type { EditorView } from '@prosekit/pm/view'
|
|
7
|
+
|
|
8
|
+
import { defineFacet } from '../../facets/facet'
|
|
9
|
+
import { defineFacetPayload } from '../../facets/facet-extension'
|
|
10
|
+
import type { PlainExtension } from '../../types/extension'
|
|
11
|
+
import {
|
|
12
|
+
pluginFacet,
|
|
13
|
+
type PluginPayload,
|
|
14
|
+
} from '../plugin'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A function that is called when the editor view is mounted.
|
|
18
|
+
*
|
|
19
|
+
* @param view - The editor view.
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export type MountHandler = (view: EditorView) => void
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A function that is called when the editor state is updated.
|
|
27
|
+
*
|
|
28
|
+
* @param view - The editor view.
|
|
29
|
+
* @param prevState - The previous editor state.
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
export type UpdateHandler = (view: EditorView, prevState: EditorState) => void
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A function that is called when the editor view is unmounted.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export type UnmountHandler = () => void
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Registers a event handler that is called when the editor view is mounted.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export function defineMountHandler(handler: MountHandler): PlainExtension {
|
|
48
|
+
return definePluginViewFacetPayload(['mount', handler])
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Registers a event handler that is called when the editor state is updated.
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
export function defineUpdateHandler(handler: UpdateHandler): PlainExtension {
|
|
57
|
+
return definePluginViewFacetPayload(['update', handler])
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Registers a event handler that is called when the editor view is unmounted.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export function defineUnmountHandler(handler: UnmountHandler): PlainExtension {
|
|
66
|
+
return definePluginViewFacetPayload(['unmount', handler])
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function definePluginViewFacetPayload(
|
|
70
|
+
input: PluginViewHandlerArgs,
|
|
71
|
+
): PlainExtension {
|
|
72
|
+
return defineFacetPayload(pluginViewFacet, [input]) as PlainExtension
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
type PluginViewHandlerArgs =
|
|
76
|
+
| ['mount', MountHandler]
|
|
77
|
+
| ['update', UpdateHandler]
|
|
78
|
+
| ['unmount', UnmountHandler]
|
|
79
|
+
|
|
80
|
+
const pluginViewFacet = defineFacet<PluginViewHandlerArgs, PluginPayload>({
|
|
81
|
+
reduce: () => {
|
|
82
|
+
let mountHandlers: MountHandler[] = []
|
|
83
|
+
let updateHandlers: UpdateHandler[] = []
|
|
84
|
+
let unmountHandlers: UnmountHandler[] = []
|
|
85
|
+
|
|
86
|
+
const plugin = new ProseMirrorPlugin({
|
|
87
|
+
key: pluginKey,
|
|
88
|
+
view: (view) => {
|
|
89
|
+
// Run all handlers after the view is mounted
|
|
90
|
+
mountHandlers.forEach((fn) => fn(view))
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
update: (view, prevState) => {
|
|
94
|
+
updateHandlers.forEach((fn) => fn(view, prevState))
|
|
95
|
+
},
|
|
96
|
+
destroy: () => {
|
|
97
|
+
unmountHandlers.forEach((fn) => fn())
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const register = (input: PluginViewHandlerArgs[]) => {
|
|
104
|
+
mountHandlers = []
|
|
105
|
+
updateHandlers = []
|
|
106
|
+
unmountHandlers = []
|
|
107
|
+
|
|
108
|
+
for (const args of input) {
|
|
109
|
+
switch (args[0]) {
|
|
110
|
+
case 'mount':
|
|
111
|
+
mountHandlers.push(args[1])
|
|
112
|
+
break
|
|
113
|
+
case 'update':
|
|
114
|
+
updateHandlers.push(args[1])
|
|
115
|
+
break
|
|
116
|
+
case 'unmount':
|
|
117
|
+
unmountHandlers.push(args[1])
|
|
118
|
+
break
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return function reducer(input: PluginViewHandlerArgs[]) {
|
|
124
|
+
register(input)
|
|
125
|
+
return plugin
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
parent: pluginFacet,
|
|
129
|
+
singleton: true,
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const pluginKey = new PluginKey('prosekit-plugin-view-handler')
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
history,
|
|
3
|
+
redo,
|
|
4
|
+
undo,
|
|
5
|
+
} from '@prosekit/pm/history'
|
|
6
|
+
|
|
7
|
+
import { union } from '../editor/union'
|
|
8
|
+
import type { Extension } from '../types/extension'
|
|
9
|
+
import { isApple } from '../utils/env'
|
|
10
|
+
|
|
11
|
+
import { defineCommands } from './command'
|
|
12
|
+
import {
|
|
13
|
+
defineKeymap,
|
|
14
|
+
type Keymap,
|
|
15
|
+
} from './keymap'
|
|
16
|
+
import { definePlugin } from './plugin'
|
|
17
|
+
|
|
18
|
+
const keymap: Keymap = {
|
|
19
|
+
'Mod-z': undo,
|
|
20
|
+
'Shift-Mod-z': redo,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!isApple) {
|
|
24
|
+
keymap['Mod-y'] = redo
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const commands = {
|
|
28
|
+
undo: () => undo,
|
|
29
|
+
redo: () => redo,
|
|
30
|
+
} as const
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options for {@link defineHistory}.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export interface HistoryOptions {
|
|
38
|
+
/**
|
|
39
|
+
* The amount of history events that are collected before the oldest events
|
|
40
|
+
* are discarded.
|
|
41
|
+
*
|
|
42
|
+
* @default 200
|
|
43
|
+
*/
|
|
44
|
+
depth?: number
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The delay in milliseconds between changes after which a new group should be
|
|
48
|
+
* started.
|
|
49
|
+
*
|
|
50
|
+
* @default 250
|
|
51
|
+
*/
|
|
52
|
+
newGroupDelay?: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export type HistoryExtension = Extension<{
|
|
59
|
+
Commands: {
|
|
60
|
+
undo: []
|
|
61
|
+
redo: []
|
|
62
|
+
}
|
|
63
|
+
}>
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Add undo/redo history to the editor.
|
|
67
|
+
*
|
|
68
|
+
* @param options
|
|
69
|
+
*
|
|
70
|
+
* @public
|
|
71
|
+
*/
|
|
72
|
+
export function defineHistory({
|
|
73
|
+
depth = 200,
|
|
74
|
+
newGroupDelay = 250,
|
|
75
|
+
}: HistoryOptions = {}): HistoryExtension {
|
|
76
|
+
return union(
|
|
77
|
+
definePlugin(history({ depth, newGroupDelay })),
|
|
78
|
+
defineKeymap(keymap),
|
|
79
|
+
defineCommands(commands),
|
|
80
|
+
)
|
|
81
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
baseKeymap,
|
|
3
|
+
chainCommands,
|
|
4
|
+
createParagraphNear,
|
|
5
|
+
deleteSelection,
|
|
6
|
+
joinTextblockBackward,
|
|
7
|
+
liftEmptyBlock,
|
|
8
|
+
newlineInCode,
|
|
9
|
+
selectNodeBackward,
|
|
10
|
+
} from '@prosekit/pm/commands'
|
|
11
|
+
import { splitSplittableBlock } from 'prosemirror-splittable'
|
|
12
|
+
|
|
13
|
+
import { withPriority } from '../editor/with-priority'
|
|
14
|
+
import type { PlainExtension } from '../types/extension'
|
|
15
|
+
import { Priority } from '../types/priority'
|
|
16
|
+
|
|
17
|
+
import { defineKeymap } from './keymap'
|
|
18
|
+
|
|
19
|
+
// Replace `splitBlock` with `splitSplittableBlock`
|
|
20
|
+
const customEnter = chainCommands(
|
|
21
|
+
newlineInCode,
|
|
22
|
+
createParagraphNear,
|
|
23
|
+
liftEmptyBlock,
|
|
24
|
+
splitSplittableBlock,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
// Replace `joinBackward` with `joinTextblockBackward`
|
|
28
|
+
const customBackspace = chainCommands(
|
|
29
|
+
deleteSelection,
|
|
30
|
+
joinTextblockBackward,
|
|
31
|
+
selectNodeBackward,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const customBaseKeymap = {
|
|
35
|
+
...baseKeymap,
|
|
36
|
+
Enter: customEnter,
|
|
37
|
+
Backspace: customBackspace,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export type BaseKeymapExtension = PlainExtension
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Defines some basic key bindings.
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
export function defineBaseKeymap(options?: {
|
|
51
|
+
/**
|
|
52
|
+
* The priority of the keymap.
|
|
53
|
+
*
|
|
54
|
+
* @default Priority.low
|
|
55
|
+
*/
|
|
56
|
+
priority?: Priority
|
|
57
|
+
}): BaseKeymapExtension {
|
|
58
|
+
const priority = options?.priority ?? Priority.low
|
|
59
|
+
return withPriority(defineKeymap(customBaseKeymap), priority)
|
|
60
|
+
}
|