@prosekit/core 0.8.3 → 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.
Files changed (168) hide show
  1. package/dist/editor-CfkZ4TNU.d.ts +748 -0
  2. package/dist/editor-CfkZ4TNU.d.ts.map +1 -0
  3. package/dist/{editor-DlGlYOp-.js → editor-CizSwUN8.js} +76 -168
  4. package/dist/editor-CizSwUN8.js.map +1 -0
  5. package/dist/prosekit-core-test.d.ts +20 -19
  6. package/dist/prosekit-core-test.d.ts.map +1 -0
  7. package/dist/prosekit-core-test.js +4 -5
  8. package/dist/prosekit-core-test.js.map +1 -0
  9. package/dist/prosekit-core.d.ts +766 -743
  10. package/dist/prosekit-core.d.ts.map +1 -0
  11. package/dist/prosekit-core.js +26 -43
  12. package/dist/prosekit-core.js.map +1 -0
  13. package/package.json +12 -9
  14. package/src/commands/add-mark.ts +53 -0
  15. package/src/commands/expand-mark.ts +96 -0
  16. package/src/commands/insert-default-block.spec.ts +102 -0
  17. package/src/commands/insert-default-block.ts +49 -0
  18. package/src/commands/insert-node.ts +71 -0
  19. package/src/commands/insert-text.ts +24 -0
  20. package/src/commands/remove-mark.ts +54 -0
  21. package/src/commands/remove-node.ts +43 -0
  22. package/src/commands/select-all.ts +16 -0
  23. package/src/commands/set-block-type.ts +64 -0
  24. package/src/commands/set-node-attrs.ts +68 -0
  25. package/src/commands/toggle-mark.ts +65 -0
  26. package/src/commands/toggle-node.ts +47 -0
  27. package/src/commands/toggle-wrap.spec.ts +35 -0
  28. package/src/commands/toggle-wrap.ts +42 -0
  29. package/src/commands/unset-block-type.spec.ts +49 -0
  30. package/src/commands/unset-block-type.ts +84 -0
  31. package/src/commands/unset-mark.spec.ts +35 -0
  32. package/src/commands/unset-mark.ts +38 -0
  33. package/src/commands/wrap.ts +50 -0
  34. package/src/editor/action.spec.ts +143 -0
  35. package/src/editor/action.ts +248 -0
  36. package/src/editor/editor.spec.ts +186 -0
  37. package/src/editor/editor.ts +563 -0
  38. package/src/editor/union.spec.ts +108 -0
  39. package/src/editor/union.ts +47 -0
  40. package/src/editor/with-priority.ts +25 -0
  41. package/src/error.ts +28 -0
  42. package/src/extensions/clipboard-serializer.ts +107 -0
  43. package/src/extensions/command.ts +121 -0
  44. package/src/extensions/default-state.spec.ts +60 -0
  45. package/src/extensions/default-state.ts +76 -0
  46. package/src/extensions/doc.ts +31 -0
  47. package/src/extensions/events/doc-change.ts +34 -0
  48. package/src/extensions/events/dom-event.spec.ts +70 -0
  49. package/src/extensions/events/dom-event.ts +117 -0
  50. package/src/extensions/events/editor-event.ts +293 -0
  51. package/src/extensions/events/focus.spec.ts +50 -0
  52. package/src/extensions/events/focus.ts +28 -0
  53. package/src/extensions/events/plugin-view.ts +132 -0
  54. package/src/extensions/history.ts +81 -0
  55. package/src/extensions/keymap-base.ts +60 -0
  56. package/src/extensions/keymap.spec.ts +89 -0
  57. package/src/extensions/keymap.ts +96 -0
  58. package/src/extensions/mark-spec.spec.ts +177 -0
  59. package/src/extensions/mark-spec.ts +181 -0
  60. package/src/extensions/mark-view-effect.ts +85 -0
  61. package/src/extensions/mark-view.ts +43 -0
  62. package/src/extensions/node-spec.spec.ts +224 -0
  63. package/src/extensions/node-spec.ts +199 -0
  64. package/src/extensions/node-view-effect.ts +85 -0
  65. package/src/extensions/node-view.ts +43 -0
  66. package/src/extensions/paragraph.ts +61 -0
  67. package/src/extensions/plugin.ts +91 -0
  68. package/src/extensions/text.ts +34 -0
  69. package/src/facets/base-extension.ts +54 -0
  70. package/src/facets/command.ts +21 -0
  71. package/src/facets/facet-extension.spec.ts +173 -0
  72. package/src/facets/facet-extension.ts +53 -0
  73. package/src/facets/facet-node.spec.ts +265 -0
  74. package/src/facets/facet-node.ts +185 -0
  75. package/src/facets/facet-types.ts +9 -0
  76. package/src/facets/facet.spec.ts +76 -0
  77. package/src/facets/facet.ts +84 -0
  78. package/src/facets/root.ts +44 -0
  79. package/src/facets/schema-spec.ts +30 -0
  80. package/src/facets/schema.ts +26 -0
  81. package/src/facets/state.ts +57 -0
  82. package/src/facets/union-extension.ts +41 -0
  83. package/src/index.ts +302 -0
  84. package/src/test/index.ts +4 -0
  85. package/src/test/test-builder.ts +68 -0
  86. package/src/test/test-editor.spec.ts +104 -0
  87. package/src/test/test-editor.ts +113 -0
  88. package/src/testing/index.ts +283 -0
  89. package/src/testing/keyboard.ts +5 -0
  90. package/src/types/any-function.ts +4 -0
  91. package/src/types/assert-type-equal.ts +8 -0
  92. package/src/types/attrs.ts +32 -0
  93. package/src/types/base-node-view-options.ts +33 -0
  94. package/src/types/dom-node.ts +1 -0
  95. package/src/types/extension-command.ts +52 -0
  96. package/src/types/extension-mark.ts +15 -0
  97. package/src/types/extension-node.ts +15 -0
  98. package/src/types/extension.spec.ts +56 -0
  99. package/src/types/extension.ts +168 -0
  100. package/src/types/model.ts +54 -0
  101. package/src/types/object-entries.ts +13 -0
  102. package/src/types/pick-string-literal.spec.ts +10 -0
  103. package/src/types/pick-string-literal.ts +6 -0
  104. package/src/types/pick-sub-type.spec.ts +20 -0
  105. package/src/types/pick-sub-type.ts +6 -0
  106. package/src/types/priority.ts +12 -0
  107. package/src/types/setter.ts +4 -0
  108. package/src/types/simplify-deeper.spec.ts +40 -0
  109. package/src/types/simplify-deeper.ts +6 -0
  110. package/src/types/simplify-union.spec.ts +21 -0
  111. package/src/types/simplify-union.ts +11 -0
  112. package/src/utils/array-grouping.spec.ts +29 -0
  113. package/src/utils/array-grouping.ts +25 -0
  114. package/src/utils/array.ts +21 -0
  115. package/src/utils/assert.ts +13 -0
  116. package/src/utils/attrs-match.ts +20 -0
  117. package/src/utils/can-use-regex-lookbehind.ts +12 -0
  118. package/src/utils/clsx.spec.ts +14 -0
  119. package/src/utils/clsx.ts +12 -0
  120. package/src/utils/collect-children.ts +21 -0
  121. package/src/utils/collect-nodes.ts +37 -0
  122. package/src/utils/combine-event-handlers.spec.ts +27 -0
  123. package/src/utils/combine-event-handlers.ts +27 -0
  124. package/src/utils/contains-inline-node.ts +17 -0
  125. package/src/utils/deep-equals.spec.ts +26 -0
  126. package/src/utils/deep-equals.ts +29 -0
  127. package/src/utils/default-block-at.ts +15 -0
  128. package/src/utils/editor-content.spec.ts +47 -0
  129. package/src/utils/editor-content.ts +77 -0
  130. package/src/utils/env.ts +6 -0
  131. package/src/utils/find-parent-node-of-type.ts +29 -0
  132. package/src/utils/find-parent-node.spec.ts +68 -0
  133. package/src/utils/find-parent-node.ts +55 -0
  134. package/src/utils/get-custom-selection.ts +19 -0
  135. package/src/utils/get-dom-api.ts +56 -0
  136. package/src/utils/get-id.spec.ts +14 -0
  137. package/src/utils/get-id.ts +13 -0
  138. package/src/utils/get-mark-type.ts +20 -0
  139. package/src/utils/get-node-type.ts +20 -0
  140. package/src/utils/get-node-types.ts +19 -0
  141. package/src/utils/includes-mark.ts +18 -0
  142. package/src/utils/is-at-block-start.ts +26 -0
  143. package/src/utils/is-in-code-block.ts +18 -0
  144. package/src/utils/is-mark-absent.spec.ts +53 -0
  145. package/src/utils/is-mark-absent.ts +42 -0
  146. package/src/utils/is-mark-active.ts +27 -0
  147. package/src/utils/is-node-active.ts +25 -0
  148. package/src/utils/is-subset.spec.ts +12 -0
  149. package/src/utils/is-subset.ts +11 -0
  150. package/src/utils/maybe-run.spec.ts +39 -0
  151. package/src/utils/maybe-run.ts +11 -0
  152. package/src/utils/merge-objects.spec.ts +30 -0
  153. package/src/utils/merge-objects.ts +11 -0
  154. package/src/utils/merge-specs.ts +35 -0
  155. package/src/utils/object-equal.spec.ts +26 -0
  156. package/src/utils/object-equal.ts +28 -0
  157. package/src/utils/output-spec.test.ts +95 -0
  158. package/src/utils/output-spec.ts +130 -0
  159. package/src/utils/parse.spec.ts +46 -0
  160. package/src/utils/parse.ts +321 -0
  161. package/src/utils/remove-undefined-values.spec.ts +15 -0
  162. package/src/utils/remove-undefined-values.ts +9 -0
  163. package/src/utils/set-selection-around.ts +11 -0
  164. package/src/utils/type-assertion.ts +91 -0
  165. package/src/utils/unicode.spec.ts +10 -0
  166. package/src/utils/unicode.ts +4 -0
  167. package/src/utils/with-skip-code-block.ts +15 -0
  168. package/dist/editor-OUH5V8BA.d.ts +0 -754
package/src/index.ts ADDED
@@ -0,0 +1,302 @@
1
+ export {
2
+ addMark,
3
+ type AddMarkOptions,
4
+ } from './commands/add-mark'
5
+ export {
6
+ expandMark,
7
+ type ExpandMarkOptions,
8
+ } from './commands/expand-mark'
9
+ export {
10
+ insertDefaultBlock,
11
+ type InsertDefaultBlockOptions,
12
+ } from './commands/insert-default-block'
13
+ export {
14
+ insertNode,
15
+ type InsertNodeOptions,
16
+ } from './commands/insert-node'
17
+ export {
18
+ removeMark,
19
+ type RemoveMarkOptions,
20
+ } from './commands/remove-mark'
21
+ export {
22
+ removeNode,
23
+ type RemoveNodeOptions,
24
+ } from './commands/remove-node'
25
+ export {
26
+ setBlockType,
27
+ type SetBlockTypeOptions,
28
+ } from './commands/set-block-type'
29
+ export {
30
+ setNodeAttrs,
31
+ type SetNodeAttrsOptions,
32
+ } from './commands/set-node-attrs'
33
+ export {
34
+ toggleMark,
35
+ type ToggleMarkOptions,
36
+ } from './commands/toggle-mark'
37
+ export {
38
+ toggleNode,
39
+ type ToggleNodeOptions,
40
+ } from './commands/toggle-node'
41
+ export {
42
+ toggleWrap,
43
+ type ToggleWrapOptions,
44
+ } from './commands/toggle-wrap'
45
+ export {
46
+ unsetBlockType,
47
+ type UnsetBlockTypeOptions,
48
+ } from './commands/unset-block-type'
49
+ export {
50
+ unsetMark,
51
+ type UnsetMarkOptions,
52
+ } from './commands/unset-mark'
53
+ export {
54
+ wrap,
55
+ type WrapOptions,
56
+ } from './commands/wrap'
57
+ export type {
58
+ MarkAction,
59
+ MarkBuilder,
60
+ NodeAction,
61
+ NodeBuilder,
62
+ NodeChild,
63
+ } from './editor/action'
64
+ export {
65
+ createEditor,
66
+ Editor,
67
+ type EditorOptions,
68
+ } from './editor/editor'
69
+ export { union } from './editor/union'
70
+ export { withPriority } from './editor/with-priority'
71
+ export {
72
+ EditorNotFoundError,
73
+ ProseKitError,
74
+ } from './error'
75
+ export {
76
+ defineClipboardSerializer,
77
+ type ClipboardSerializerOptions,
78
+ } from './extensions/clipboard-serializer'
79
+ export {
80
+ defineBaseCommands,
81
+ defineCommands,
82
+ type BaseCommandsExtension,
83
+ } from './extensions/command'
84
+ export {
85
+ defineDefaultState,
86
+ type DefaultStateOptions,
87
+ } from './extensions/default-state'
88
+ export {
89
+ defineDoc,
90
+ type DocExtension,
91
+ } from './extensions/doc'
92
+ export {
93
+ defineDocChangeHandler,
94
+ type DocChangeHandler,
95
+ } from './extensions/events/doc-change'
96
+ export {
97
+ defineDOMEventHandler,
98
+ type DOMEventHandler,
99
+ } from './extensions/events/dom-event'
100
+ export {
101
+ defineClickHandler,
102
+ defineClickOnHandler,
103
+ defineDoubleClickHandler,
104
+ defineDoubleClickOnHandler,
105
+ defineDropHandler,
106
+ defineKeyDownHandler,
107
+ defineKeyPressHandler,
108
+ definePasteHandler,
109
+ defineScrollToSelectionHandler,
110
+ defineTextInputHandler,
111
+ defineTripleClickHandler,
112
+ defineTripleClickOnHandler,
113
+ editorEventFacet,
114
+ type ClickHandler,
115
+ type ClickOnHandler,
116
+ type DoubleClickHandler,
117
+ type DoubleClickOnHandler,
118
+ type DropHandler,
119
+ type EditorEventPayload,
120
+ type KeyDownHandler,
121
+ type KeyPressHandler,
122
+ type PasteHandler,
123
+ type ScrollToSelectionHandler,
124
+ type TextInputHandler,
125
+ type TripleClickHandler,
126
+ type TripleClickOnHandler,
127
+ } from './extensions/events/editor-event'
128
+ export {
129
+ defineFocusChangeHandler,
130
+ type FocusChangeHandler,
131
+ } from './extensions/events/focus'
132
+ export {
133
+ defineMountHandler,
134
+ defineUnmountHandler,
135
+ defineUpdateHandler,
136
+ type MountHandler,
137
+ type UnmountHandler,
138
+ type UpdateHandler,
139
+ } from './extensions/events/plugin-view'
140
+ export {
141
+ defineHistory,
142
+ type HistoryExtension,
143
+ type HistoryOptions,
144
+ } from './extensions/history'
145
+ export {
146
+ defineKeymap,
147
+ keymapFacet,
148
+ type Keymap,
149
+ type KeymapPayload,
150
+ } from './extensions/keymap'
151
+ export {
152
+ defineBaseKeymap,
153
+ type BaseKeymapExtension,
154
+ } from './extensions/keymap-base'
155
+ export {
156
+ defineMarkAttr,
157
+ defineMarkSpec,
158
+ type MarkAttrOptions,
159
+ type MarkSpecOptions,
160
+ } from './extensions/mark-spec'
161
+ export {
162
+ defineMarkView,
163
+ type MarkViewOptions,
164
+ } from './extensions/mark-view'
165
+ export {
166
+ defineMarkViewComponent,
167
+ defineMarkViewFactory,
168
+ type MarkViewComponentOptions,
169
+ type MarkViewFactoryOptions,
170
+ } from './extensions/mark-view-effect'
171
+ export {
172
+ defineNodeAttr,
173
+ defineNodeSpec,
174
+ type NodeAttrOptions,
175
+ type NodeSpecOptions,
176
+ } from './extensions/node-spec'
177
+ export {
178
+ defineNodeView,
179
+ type NodeViewOptions,
180
+ } from './extensions/node-view'
181
+ export {
182
+ defineNodeViewComponent,
183
+ defineNodeViewFactory,
184
+ type NodeViewComponentOptions,
185
+ type NodeViewFactoryOptions,
186
+ } from './extensions/node-view-effect'
187
+ export {
188
+ defineParagraph,
189
+ type ParagraphExtension,
190
+ } from './extensions/paragraph'
191
+ export {
192
+ definePlugin,
193
+ pluginFacet,
194
+ type PluginPayload,
195
+ } from './extensions/plugin'
196
+ export {
197
+ defineText,
198
+ type TextExtension,
199
+ } from './extensions/text'
200
+ export {
201
+ defineFacet,
202
+ type Facet,
203
+ } from './facets/facet'
204
+ export { defineFacetPayload } from './facets/facet-extension'
205
+ export type { AnyFunction } from './types/any-function'
206
+ export type {
207
+ AnyAttrs,
208
+ AttrSpec,
209
+ } from './types/attrs'
210
+ export type { BaseNodeViewOptions } from './types/base-node-view-options'
211
+ export type {
212
+ Extension,
213
+ ExtensionTyping,
214
+ ExtractCommandActions,
215
+ ExtractCommandAppliers,
216
+ ExtractCommandCreators,
217
+ ExtractCommands,
218
+ ExtractMarkActions,
219
+ ExtractMarks,
220
+ ExtractNodeActions,
221
+ ExtractNodes,
222
+ ExtractTyping,
223
+ PlainExtension,
224
+ Union,
225
+ UnionExtension,
226
+ } from './types/extension'
227
+ export type {
228
+ CommandAction,
229
+ CommandTyping,
230
+ } from './types/extension-command'
231
+ export type {
232
+ MarkTyping,
233
+ ToMarkAction,
234
+ } from './types/extension-mark'
235
+ export type {
236
+ NodeTyping,
237
+ ToNodeAction,
238
+ } from './types/extension-node'
239
+ export type {
240
+ NodeJSON,
241
+ SelectionJSON,
242
+ StateJSON,
243
+ StepJSON,
244
+ } from './types/model'
245
+ export type { PickSubType } from './types/pick-sub-type'
246
+ export { Priority } from './types/priority'
247
+ export type { SimplifyDeeper } from './types/simplify-deeper'
248
+ export type { SimplifyUnion } from './types/simplify-union'
249
+ export { assert } from './utils/assert'
250
+ export { canUseRegexLookbehind } from './utils/can-use-regex-lookbehind'
251
+ export { clsx } from './utils/clsx'
252
+ export { collectChildren } from './utils/collect-children'
253
+ export {
254
+ collectNodes,
255
+ type NodeContent,
256
+ } from './utils/collect-nodes'
257
+ export { containsInlineNode } from './utils/contains-inline-node'
258
+ export { defaultBlockAt } from './utils/default-block-at'
259
+ export { isApple } from './utils/env'
260
+ export {
261
+ findParentNode,
262
+ type FindParentNodeResult,
263
+ } from './utils/find-parent-node'
264
+ export { findParentNodeOfType } from './utils/find-parent-node-of-type'
265
+ export { getId as _getId } from './utils/get-id'
266
+ export { getMarkType } from './utils/get-mark-type'
267
+ export { getNodeType } from './utils/get-node-type'
268
+ export { isAtBlockStart } from './utils/is-at-block-start'
269
+ export { isInCodeBlock } from './utils/is-in-code-block'
270
+ export { isMarkAbsent } from './utils/is-mark-absent'
271
+ export { isMarkActive } from './utils/is-mark-active'
272
+ export { maybeRun } from './utils/maybe-run'
273
+ export {
274
+ elementFromJSON,
275
+ elementFromNode,
276
+ htmlFromJSON,
277
+ htmlFromNode,
278
+ jsonFromHTML,
279
+ jsonFromNode,
280
+ jsonFromState,
281
+ nodeFromElement,
282
+ nodeFromHTML,
283
+ nodeFromJSON,
284
+ stateFromJSON,
285
+ type DOMDocumentOptions,
286
+ type DOMParserOptions,
287
+ type DOMSerializerOptions,
288
+ type JSONParserOptions,
289
+ } from './utils/parse'
290
+ export { setSelectionAround } from './utils/set-selection-around'
291
+ export {
292
+ isAllSelection,
293
+ isFragment,
294
+ isMark,
295
+ isNodeSelection,
296
+ isProseMirrorNode,
297
+ isSelection,
298
+ isSlice,
299
+ isTextSelection,
300
+ } from './utils/type-assertion'
301
+ export * from './utils/unicode'
302
+ export { withSkipCodeBlock } from './utils/with-skip-code-block'
@@ -0,0 +1,4 @@
1
+ export {
2
+ createTestEditor,
3
+ type TestEditor,
4
+ } from './test-editor'
@@ -0,0 +1,68 @@
1
+ import type { ProseMirrorNode } from '@prosekit/pm/model'
2
+
3
+ import type {
4
+ ApplyMarkFunction,
5
+ CreateNodeFunction,
6
+ } from '../editor/action'
7
+ import { assert } from '../utils/assert'
8
+
9
+ type Tags = Record<string, number>
10
+ export type TaggedProseMirrorNode = ProseMirrorNode & { tags?: Tags }
11
+
12
+ export const createNodeForTest: CreateNodeFunction = (
13
+ type,
14
+ attrs,
15
+ children: TaggedProseMirrorNode[],
16
+ ): TaggedProseMirrorNode => {
17
+ const tags: Tags = {}
18
+ const isTopNode = type === type.schema.topNodeType
19
+ let pos = isTopNode ? 0 : 1
20
+ const normalizedChildren: TaggedProseMirrorNode[] = []
21
+
22
+ for (const child of children) {
23
+ if (child.tags) {
24
+ for (const [key, value] of Object.entries(child.tags)) {
25
+ tags[key] = pos + value
26
+ }
27
+ normalizedChildren.push(child)
28
+ pos += child.nodeSize
29
+ } else if (child.isText) {
30
+ const text = child.text!
31
+ const re = /<(a|b)>/g
32
+ let i = 0
33
+ let out = ''
34
+ for (const match of text.matchAll(re)) {
35
+ out += text.slice(i, match.index)
36
+ tags[match[1]] = pos + out.length
37
+ i = match.index + match[0].length
38
+ }
39
+ out += text.slice(i)
40
+ if (out) {
41
+ normalizedChildren.push(child.type.schema.text(out).mark(child.marks))
42
+ pos += out.length
43
+ }
44
+ } else {
45
+ normalizedChildren.push(child)
46
+ pos += child.nodeSize
47
+ }
48
+ }
49
+
50
+ const node: TaggedProseMirrorNode | null = type.createAndFill(
51
+ attrs,
52
+ normalizedChildren,
53
+ )
54
+ assert(node, `Failed to create node ${type.name}`)
55
+ node.tags = tags
56
+ return node
57
+ }
58
+
59
+ export const applyMarkForTest: ApplyMarkFunction = (
60
+ mark,
61
+ children: TaggedProseMirrorNode[],
62
+ ): TaggedProseMirrorNode[] => {
63
+ return children.map((node) => {
64
+ const newNode: TaggedProseMirrorNode = node.mark(mark.addToSet(node.marks))
65
+ newNode.tags = node.tags
66
+ return newNode
67
+ })
68
+ }
@@ -0,0 +1,104 @@
1
+ import {
2
+ describe,
3
+ expect,
4
+ it,
5
+ } from 'vitest'
6
+
7
+ import { setupTest } from '../testing'
8
+
9
+ describe('TestEditor', () => {
10
+ it('should create nodes and marks', () => {
11
+ const { editor, m, n } = setupTest()
12
+
13
+ const doc = n.doc(n.paragraph('Hello ', m.bold('world!')))
14
+ editor.set(doc)
15
+ expect(editor.state.doc.toJSON()).toMatchInlineSnapshot(`
16
+ {
17
+ "content": [
18
+ {
19
+ "content": [
20
+ {
21
+ "text": "Hello ",
22
+ "type": "text",
23
+ },
24
+ {
25
+ "marks": [
26
+ {
27
+ "type": "bold",
28
+ },
29
+ ],
30
+ "text": "world!",
31
+ "type": "text",
32
+ },
33
+ ],
34
+ "type": "paragraph",
35
+ },
36
+ ],
37
+ "type": "doc",
38
+ }
39
+ `)
40
+ })
41
+
42
+ it('should set text selection', () => {
43
+ const { editor, m, n } = setupTest()
44
+
45
+ editor.set(n.doc(n.paragraph('Hello ', m.bold('<a>world<b>!'))))
46
+ expect(editor.state.selection.toJSON()).toMatchInlineSnapshot(`
47
+ {
48
+ "anchor": 7,
49
+ "head": 12,
50
+ "type": "text",
51
+ }
52
+ `)
53
+ expect(
54
+ editor.state.selection.content().content.toString(),
55
+ ).toMatchInlineSnapshot(`"<paragraph(bold("world"))>"`)
56
+
57
+ editor.set(n.doc(n.paragraph('Hello ', m.bold('<b>world<a>!'))))
58
+ expect(editor.state.selection.toJSON()).toMatchInlineSnapshot(`
59
+ {
60
+ "anchor": 12,
61
+ "head": 7,
62
+ "type": "text",
63
+ }
64
+ `)
65
+ expect(
66
+ editor.state.selection.content().content.toString(),
67
+ ).toMatchInlineSnapshot(`"<paragraph(bold("world"))>"`)
68
+
69
+ editor.set(n.doc(n.paragraph('Hello ', m.bold('<a>world!'))))
70
+ expect(editor.state.selection.toJSON()).toMatchInlineSnapshot(`
71
+ {
72
+ "anchor": 7,
73
+ "head": 7,
74
+ "type": "text",
75
+ }
76
+ `)
77
+ })
78
+
79
+ it('should set node selection', () => {
80
+ const { editor, n } = setupTest()
81
+
82
+ editor.set(n.doc('<a>', n.paragraph('foo')))
83
+ expect(editor.state.selection.toJSON()).toMatchInlineSnapshot(`
84
+ {
85
+ "anchor": 0,
86
+ "type": "node",
87
+ }
88
+ `)
89
+ expect(
90
+ editor.state.selection.content().content.toString(),
91
+ ).toMatchInlineSnapshot(`"<paragraph("foo")>"`)
92
+
93
+ editor.set(n.doc(n.paragraph('foo'), '<a>', n.paragraph('bar')))
94
+ expect(editor.state.selection.toJSON()).toMatchInlineSnapshot(`
95
+ {
96
+ "anchor": 5,
97
+ "type": "node",
98
+ }
99
+ `)
100
+ expect(
101
+ editor.state.selection.content().content.toString(),
102
+ ).toMatchInlineSnapshot(`"<paragraph("bar")>"`)
103
+ })
104
+ })
@@ -0,0 +1,113 @@
1
+ import type { ProseMirrorNode } from '@prosekit/pm/model'
2
+ import {
3
+ NodeSelection,
4
+ TextSelection,
5
+ type Selection,
6
+ } from '@prosekit/pm/state'
7
+
8
+ import {
9
+ createMarkActions,
10
+ createNodeActions,
11
+ } from '../editor/action'
12
+ import {
13
+ Editor,
14
+ EditorInstance,
15
+ setupEditorExtension,
16
+ type EditorOptions,
17
+ } from '../editor/editor'
18
+ import type { Extension } from '../types/extension'
19
+ import type {
20
+ NodeJSON,
21
+ SelectionJSON,
22
+ } from '../types/model'
23
+ import { isProseMirrorNode } from '../utils/type-assertion'
24
+
25
+ import {
26
+ applyMarkForTest,
27
+ createNodeForTest,
28
+ type TaggedProseMirrorNode,
29
+ } from './test-builder'
30
+
31
+ function maybeResolve(doc: ProseMirrorNode, pos?: number) {
32
+ if (pos != null) {
33
+ return doc.resolve(pos)
34
+ }
35
+ return undefined
36
+ }
37
+
38
+ function getSelection(doc: TaggedProseMirrorNode): Selection {
39
+ const tags = doc.tags
40
+ const $a = maybeResolve(doc, tags?.a)
41
+ const $b = maybeResolve(doc, tags?.b)
42
+
43
+ if ($a) {
44
+ if ($a.parent.inlineContent) {
45
+ return new TextSelection($a, $b)
46
+ } else {
47
+ return new NodeSelection($a)
48
+ }
49
+ }
50
+ return TextSelection.atStart(doc)
51
+ }
52
+
53
+ class TestEditorInstance extends EditorInstance {
54
+ constructor(extension: Extension) {
55
+ super(extension)
56
+ this.nodes = createNodeActions(this.schema, this.getState, createNodeForTest)
57
+ this.marks = createMarkActions(this.schema, this.getState, applyMarkForTest)
58
+ }
59
+
60
+ override setContent(
61
+ content: ProseMirrorNode | NodeJSON | string | HTMLElement,
62
+ selection?: SelectionJSON | Selection | 'start' | 'end',
63
+ ): void {
64
+ return super.setContent(
65
+ content,
66
+ isProseMirrorNode(content) && !selection
67
+ ? getSelection(content)
68
+ : selection,
69
+ )
70
+ }
71
+ }
72
+
73
+ /**
74
+ * An editor for testing purposes.
75
+ * @public
76
+ */
77
+ export class TestEditor<E extends Extension = Extension> extends Editor<E> {
78
+ constructor(instance: EditorInstance) {
79
+ super(instance)
80
+ }
81
+
82
+ /**
83
+ * Set the editor state to the given document. You can use special tokens
84
+ * `<a>` and `<b>` to set the anchor and head positions of the selection.
85
+ *
86
+ * @example
87
+ *
88
+ * ```ts
89
+ * const editor = createTestEditor({ extension })
90
+ * const n = editor.nodes
91
+ * const doc = n.doc(n.paragraph('<a>Hello<b> world!'))
92
+ * editor.set(doc) // "Hello" is selected.
93
+ * ```
94
+ */
95
+ set(doc: ProseMirrorNode): void {
96
+ return this.setContent(doc)
97
+ }
98
+
99
+ dispatchEvent(event: Event): void {
100
+ this.view.dispatchEvent(event)
101
+ }
102
+ }
103
+
104
+ /**
105
+ * @public
106
+ */
107
+ export function createTestEditor<E extends Extension>(
108
+ options: EditorOptions<E>,
109
+ ): TestEditor<E> {
110
+ const extension = setupEditorExtension(options)
111
+ const instance = new TestEditorInstance(extension)
112
+ return new TestEditor(instance)
113
+ }