@prosekit/core 0.8.3 → 0.8.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.
Files changed (170) hide show
  1. package/dist/editor-KZlceNQ1.d.ts +722 -0
  2. package/dist/editor-KZlceNQ1.d.ts.map +1 -0
  3. package/dist/{editor-DlGlYOp-.js → editor-TvRTsFdO.js} +102 -196
  4. package/dist/editor-TvRTsFdO.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 +5 -8
  8. package/dist/prosekit-core-test.js.map +1 -0
  9. package/dist/prosekit-core.d.ts +797 -792
  10. package/dist/prosekit-core.d.ts.map +1 -0
  11. package/dist/prosekit-core.js +42 -79
  12. package/dist/prosekit-core.js.map +1 -0
  13. package/package.json +14 -12
  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 +125 -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.spec.ts +153 -0
  68. package/src/extensions/plugin.ts +81 -0
  69. package/src/extensions/text.ts +34 -0
  70. package/src/facets/base-extension.ts +54 -0
  71. package/src/facets/command.ts +21 -0
  72. package/src/facets/facet-extension.spec.ts +173 -0
  73. package/src/facets/facet-extension.ts +53 -0
  74. package/src/facets/facet-node.spec.ts +265 -0
  75. package/src/facets/facet-node.ts +185 -0
  76. package/src/facets/facet-types.ts +9 -0
  77. package/src/facets/facet.spec.ts +76 -0
  78. package/src/facets/facet.ts +84 -0
  79. package/src/facets/root.ts +44 -0
  80. package/src/facets/schema-spec.ts +30 -0
  81. package/src/facets/schema.ts +26 -0
  82. package/src/facets/state.spec.ts +53 -0
  83. package/src/facets/state.ts +85 -0
  84. package/src/facets/union-extension.ts +41 -0
  85. package/src/index.ts +302 -0
  86. package/src/test/index.ts +4 -0
  87. package/src/test/test-builder.ts +68 -0
  88. package/src/test/test-editor.spec.ts +104 -0
  89. package/src/test/test-editor.ts +113 -0
  90. package/src/testing/index.ts +283 -0
  91. package/src/testing/keyboard.ts +5 -0
  92. package/src/types/any-function.ts +4 -0
  93. package/src/types/assert-type-equal.ts +8 -0
  94. package/src/types/attrs.ts +32 -0
  95. package/src/types/base-node-view-options.ts +33 -0
  96. package/src/types/dom-node.ts +1 -0
  97. package/src/types/extension-command.ts +52 -0
  98. package/src/types/extension-mark.ts +15 -0
  99. package/src/types/extension-node.ts +15 -0
  100. package/src/types/extension.spec.ts +56 -0
  101. package/src/types/extension.ts +168 -0
  102. package/src/types/model.ts +54 -0
  103. package/src/types/object-entries.ts +13 -0
  104. package/src/types/pick-string-literal.spec.ts +10 -0
  105. package/src/types/pick-string-literal.ts +6 -0
  106. package/src/types/pick-sub-type.spec.ts +20 -0
  107. package/src/types/pick-sub-type.ts +6 -0
  108. package/src/types/priority.ts +12 -0
  109. package/src/types/setter.ts +4 -0
  110. package/src/types/simplify-deeper.spec.ts +40 -0
  111. package/src/types/simplify-deeper.ts +6 -0
  112. package/src/types/simplify-union.spec.ts +21 -0
  113. package/src/types/simplify-union.ts +11 -0
  114. package/src/utils/array-grouping.spec.ts +29 -0
  115. package/src/utils/array-grouping.ts +25 -0
  116. package/src/utils/array.ts +21 -0
  117. package/src/utils/assert.ts +13 -0
  118. package/src/utils/attrs-match.ts +20 -0
  119. package/src/utils/can-use-regex-lookbehind.ts +12 -0
  120. package/src/utils/clsx.spec.ts +14 -0
  121. package/src/utils/clsx.ts +14 -0
  122. package/src/utils/collect-children.ts +21 -0
  123. package/src/utils/collect-nodes.ts +37 -0
  124. package/src/utils/combine-event-handlers.spec.ts +27 -0
  125. package/src/utils/combine-event-handlers.ts +27 -0
  126. package/src/utils/contains-inline-node.ts +17 -0
  127. package/src/utils/deep-equals.spec.ts +26 -0
  128. package/src/utils/deep-equals.ts +29 -0
  129. package/src/utils/default-block-at.ts +15 -0
  130. package/src/utils/editor-content.spec.ts +47 -0
  131. package/src/utils/editor-content.ts +77 -0
  132. package/src/utils/env.ts +6 -0
  133. package/src/utils/find-parent-node-of-type.ts +29 -0
  134. package/src/utils/find-parent-node.spec.ts +68 -0
  135. package/src/utils/find-parent-node.ts +55 -0
  136. package/src/utils/get-custom-selection.ts +19 -0
  137. package/src/utils/get-dom-api.ts +56 -0
  138. package/src/utils/get-id.spec.ts +14 -0
  139. package/src/utils/get-id.ts +13 -0
  140. package/src/utils/get-mark-type.ts +20 -0
  141. package/src/utils/get-node-type.ts +20 -0
  142. package/src/utils/get-node-types.ts +19 -0
  143. package/src/utils/includes-mark.ts +18 -0
  144. package/src/utils/is-at-block-start.ts +26 -0
  145. package/src/utils/is-in-code-block.ts +18 -0
  146. package/src/utils/is-mark-absent.spec.ts +53 -0
  147. package/src/utils/is-mark-absent.ts +42 -0
  148. package/src/utils/is-mark-active.ts +27 -0
  149. package/src/utils/is-node-active.ts +25 -0
  150. package/src/utils/is-subset.spec.ts +12 -0
  151. package/src/utils/is-subset.ts +11 -0
  152. package/src/utils/maybe-run.spec.ts +39 -0
  153. package/src/utils/maybe-run.ts +11 -0
  154. package/src/utils/merge-objects.spec.ts +30 -0
  155. package/src/utils/merge-objects.ts +11 -0
  156. package/src/utils/merge-specs.ts +35 -0
  157. package/src/utils/object-equal.spec.ts +26 -0
  158. package/src/utils/object-equal.ts +28 -0
  159. package/src/utils/output-spec.test.ts +95 -0
  160. package/src/utils/output-spec.ts +130 -0
  161. package/src/utils/parse.spec.ts +46 -0
  162. package/src/utils/parse.ts +321 -0
  163. package/src/utils/remove-undefined-values.spec.ts +15 -0
  164. package/src/utils/remove-undefined-values.ts +9 -0
  165. package/src/utils/set-selection-around.ts +11 -0
  166. package/src/utils/type-assertion.ts +91 -0
  167. package/src/utils/unicode.spec.ts +10 -0
  168. package/src/utils/unicode.ts +4 -0
  169. package/src/utils/with-skip-code-block.ts +15 -0
  170. package/dist/editor-OUH5V8BA.d.ts +0 -754
@@ -0,0 +1,53 @@
1
+ import {
2
+ describe,
3
+ expect,
4
+ it,
5
+ } from 'vitest'
6
+
7
+ import { union } from '../editor/union'
8
+ import { withPriority } from '../editor/with-priority'
9
+ import { defineDefaultState } from '../extensions/default-state'
10
+ import {
11
+ defineTestExtension,
12
+ setupTestFromExtension,
13
+ } from '../testing'
14
+ import type { NodeJSON } from '../types/model'
15
+ import { Priority } from '../types/priority'
16
+
17
+ describe('state', () => {
18
+ it('uses doc from extension with highest priority', () => {
19
+ const doc1: NodeJSON = { type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'default priority' }] }] }
20
+ const doc2: NodeJSON = { type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'highest priority' }] }] }
21
+ const doc3: NodeJSON = { type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'lowest priority' }] }] }
22
+
23
+ const extension1 = defineDefaultState({ defaultDoc: doc1 }) // default priority
24
+ const extension2 = withPriority(defineDefaultState({ defaultDoc: doc2 }), Priority.highest)
25
+ const extension3 = withPriority(defineDefaultState({ defaultDoc: doc3 }), Priority.lowest)
26
+
27
+ const combinedExtension = union(defineTestExtension(), extension1, extension2, extension3)
28
+ const { editor } = setupTestFromExtension(combinedExtension)
29
+
30
+ const docText = editor.state.doc.textContent
31
+
32
+ // The extension with the highest priority should set the doc
33
+ expect(docText).toEqual('highest priority')
34
+ })
35
+
36
+ it('uses doc from last extension when all have same priority', () => {
37
+ const doc1 = { type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'first' }] }] }
38
+ const doc2 = { type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'second' }] }] }
39
+ const doc3 = { type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'third' }] }] }
40
+
41
+ const extension1 = defineDefaultState({ defaultDoc: doc1 })
42
+ const extension2 = defineDefaultState({ defaultDoc: doc2 })
43
+ const extension3 = defineDefaultState({ defaultDoc: doc3 })
44
+
45
+ const combinedExtension = union(defineTestExtension(), extension1, extension2, extension3)
46
+ const { editor } = setupTestFromExtension(combinedExtension)
47
+
48
+ const docText = editor.state.doc.textContent
49
+
50
+ // When all have same priority, later extensions override earlier ones
51
+ expect(docText).toEqual('third')
52
+ })
53
+ })
@@ -0,0 +1,85 @@
1
+ import type {
2
+ Mark,
3
+ ProseMirrorNode,
4
+ Schema,
5
+ } from '@prosekit/pm/model'
6
+ import type { EditorStateConfig } from '@prosekit/pm/state'
7
+ import type {
8
+ Plugin,
9
+ Selection,
10
+ } from '@prosekit/pm/state'
11
+
12
+ import { toReversed } from '../utils/array'
13
+ import { assert } from '../utils/assert'
14
+
15
+ import {
16
+ defineFacet,
17
+ type Facet,
18
+ } from './facet'
19
+ import {
20
+ rootFacet,
21
+ type RootPayload,
22
+ } from './root'
23
+
24
+ export type StatePayload = (ctx: { schema: Schema }) => EditorStateConfig
25
+
26
+ export const stateFacet: Facet<StatePayload, RootPayload> = defineFacet({
27
+ reduce: () => {
28
+ // An array of state payloads from lower to higher priority.
29
+ let callbacks: StatePayload[] = []
30
+
31
+ const state: StatePayload = (ctx) => {
32
+ let doc: ProseMirrorNode | undefined
33
+ let selection: Selection | undefined
34
+ let schema: Schema | undefined = ctx.schema
35
+ const markSet = new Set<Mark>()
36
+ const pluginSet = new Set<Plugin>()
37
+
38
+ // An array of state payloads from higher to lower priority. This matches the
39
+ // order of plugins required by ProseMirror.
40
+ const reversedCallbacks = toReversed(callbacks)
41
+
42
+ for (const callback of reversedCallbacks) {
43
+ const config = callback(ctx)
44
+
45
+ doc ||= config.doc
46
+ selection ||= config.selection
47
+ schema ||= config.schema
48
+
49
+ for (const mark of (config.storedMarks ?? [])) {
50
+ markSet.add(mark)
51
+ }
52
+
53
+ for (const plugin of (config.plugins ?? [])) {
54
+ // `config.plugins` is an array of plugins from higher to lower priority.
55
+ pluginSet.add(plugin)
56
+ }
57
+ }
58
+
59
+ // If both doc and schema are provided, the schema is not needed.
60
+ if (doc && schema) {
61
+ schema = undefined
62
+ }
63
+
64
+ assert(
65
+ doc || schema,
66
+ "Can't create state without a schema nor a document",
67
+ )
68
+
69
+ return {
70
+ doc,
71
+ selection,
72
+ schema,
73
+ storedMarks: Array.from(markSet),
74
+ plugins: Array.from(pluginSet),
75
+ }
76
+ }
77
+
78
+ return function reducer(inputs) {
79
+ callbacks = inputs
80
+ return { state }
81
+ }
82
+ },
83
+ singleton: true,
84
+ parent: rootFacet,
85
+ })
@@ -0,0 +1,41 @@
1
+ import type {
2
+ Extension,
3
+ ExtensionTyping,
4
+ } from '../types/extension'
5
+ import type { Priority } from '../types/priority'
6
+ import { assert } from '../utils/assert'
7
+
8
+ import { BaseExtension } from './base-extension'
9
+ import {
10
+ unionFacetNode,
11
+ type FacetNode,
12
+ } from './facet-node'
13
+
14
+ export class UnionExtensionImpl<T extends ExtensionTyping = ExtensionTyping> extends BaseExtension<T> implements Extension<T> {
15
+ /**
16
+ * @internal
17
+ */
18
+ constructor(public extension: BaseExtension[] = []) {
19
+ super()
20
+ }
21
+
22
+ /**
23
+ * @internal
24
+ */
25
+ createTree(priority: Priority): FacetNode {
26
+ const pri = this.priority ?? priority
27
+
28
+ const extensions = [...this.extension]
29
+ extensions.sort((a, b) => (a.priority ?? pri) - (b.priority ?? pri))
30
+
31
+ const children: FacetNode[] = extensions.map((ext) => ext.getTree(pri))
32
+
33
+ assert(children.length > 0)
34
+
35
+ let node = children[0]
36
+ for (let i = 1; i < children.length; i++) {
37
+ node = unionFacetNode(node, children[i])
38
+ }
39
+ return node
40
+ }
41
+ }
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
+ })