@prosekit/extensions 0.12.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/dist/{drop-indicator-B1QHFb5m.js → drop-indicator-B_oMfeVP.js} +11 -10
  2. package/dist/drop-indicator-B_oMfeVP.js.map +1 -0
  3. package/dist/{enter-rule-CzWOZF_Z.js → enter-rule-D-p4ykfv.js} +1 -1
  4. package/dist/enter-rule-D-p4ykfv.js.map +1 -0
  5. package/dist/{file-DrfcSid-.js → file-iLVR0eM0.js} +3 -3
  6. package/dist/file-iLVR0eM0.js.map +1 -0
  7. package/dist/{index-oIc1a2f2.d.ts → index-cp1u4e0e.d.ts} +1 -1
  8. package/dist/index-cp1u4e0e.d.ts.map +1 -0
  9. package/dist/{input-rule-dmsb3j6w.js → input-rule-COGr_GBb.js} +1 -1
  10. package/dist/input-rule-COGr_GBb.js.map +1 -0
  11. package/dist/list/style.css +5 -5
  12. package/dist/list/style.css.map +1 -1
  13. package/dist/{mark-rule-BcLB4Uv2.js → mark-rule-CYe8zk4q.js} +6 -6
  14. package/dist/mark-rule-CYe8zk4q.js.map +1 -0
  15. package/dist/{paste-rule-pVb4sqvJ.js → paste-rule-BaDghcaU.js} +7 -7
  16. package/dist/paste-rule-BaDghcaU.js.map +1 -0
  17. package/dist/prosekit-extensions-autocomplete.d.ts +11 -3
  18. package/dist/prosekit-extensions-autocomplete.d.ts.map +1 -1
  19. package/dist/prosekit-extensions-autocomplete.js +171 -60
  20. package/dist/prosekit-extensions-autocomplete.js.map +1 -1
  21. package/dist/prosekit-extensions-background-color.d.ts +62 -0
  22. package/dist/prosekit-extensions-background-color.d.ts.map +1 -0
  23. package/dist/prosekit-extensions-background-color.js +76 -0
  24. package/dist/prosekit-extensions-background-color.js.map +1 -0
  25. package/dist/prosekit-extensions-blockquote.d.ts.map +1 -1
  26. package/dist/prosekit-extensions-blockquote.js +2 -2
  27. package/dist/prosekit-extensions-blockquote.js.map +1 -1
  28. package/dist/prosekit-extensions-bold.d.ts.map +1 -1
  29. package/dist/prosekit-extensions-bold.js +1 -1
  30. package/dist/prosekit-extensions-bold.js.map +1 -1
  31. package/dist/prosekit-extensions-code-block.d.ts +1 -1
  32. package/dist/prosekit-extensions-code-block.d.ts.map +1 -1
  33. package/dist/prosekit-extensions-code-block.js +4 -4
  34. package/dist/prosekit-extensions-code-block.js.map +1 -1
  35. package/dist/prosekit-extensions-code.d.ts.map +1 -1
  36. package/dist/prosekit-extensions-code.js +1 -1
  37. package/dist/prosekit-extensions-code.js.map +1 -1
  38. package/dist/prosekit-extensions-commit.d.ts +0 -1
  39. package/dist/prosekit-extensions-commit.d.ts.map +1 -1
  40. package/dist/prosekit-extensions-commit.js +1 -1
  41. package/dist/prosekit-extensions-commit.js.map +1 -1
  42. package/dist/prosekit-extensions-doc.d.ts +0 -1
  43. package/dist/prosekit-extensions-doc.d.ts.map +1 -1
  44. package/dist/prosekit-extensions-doc.js.map +1 -1
  45. package/dist/prosekit-extensions-drop-cursor.d.ts.map +1 -1
  46. package/dist/prosekit-extensions-drop-cursor.js.map +1 -1
  47. package/dist/prosekit-extensions-drop-indicator.d.ts +0 -1
  48. package/dist/prosekit-extensions-drop-indicator.d.ts.map +1 -1
  49. package/dist/prosekit-extensions-drop-indicator.js +1 -1
  50. package/dist/prosekit-extensions-enter-rule.d.ts +0 -1
  51. package/dist/prosekit-extensions-enter-rule.d.ts.map +1 -1
  52. package/dist/prosekit-extensions-enter-rule.js +1 -1
  53. package/dist/prosekit-extensions-file.d.ts +1 -1
  54. package/dist/prosekit-extensions-file.js +1 -1
  55. package/dist/prosekit-extensions-gap-cursor.d.ts +0 -1
  56. package/dist/prosekit-extensions-gap-cursor.d.ts.map +1 -1
  57. package/dist/prosekit-extensions-gap-cursor.js.map +1 -1
  58. package/dist/prosekit-extensions-hard-break.d.ts.map +1 -1
  59. package/dist/prosekit-extensions-hard-break.js.map +1 -1
  60. package/dist/prosekit-extensions-heading.d.ts.map +1 -1
  61. package/dist/prosekit-extensions-heading.js +7 -7
  62. package/dist/prosekit-extensions-heading.js.map +1 -1
  63. package/dist/prosekit-extensions-horizontal-rule.d.ts.map +1 -1
  64. package/dist/prosekit-extensions-horizontal-rule.js +1 -1
  65. package/dist/prosekit-extensions-horizontal-rule.js.map +1 -1
  66. package/dist/prosekit-extensions-image.d.ts +9 -2
  67. package/dist/prosekit-extensions-image.d.ts.map +1 -1
  68. package/dist/prosekit-extensions-image.js +17 -4
  69. package/dist/prosekit-extensions-image.js.map +1 -1
  70. package/dist/prosekit-extensions-input-rule.d.ts +0 -1
  71. package/dist/prosekit-extensions-input-rule.d.ts.map +1 -1
  72. package/dist/prosekit-extensions-input-rule.js +1 -1
  73. package/dist/prosekit-extensions-italic.d.ts.map +1 -1
  74. package/dist/prosekit-extensions-italic.js +1 -1
  75. package/dist/prosekit-extensions-italic.js.map +1 -1
  76. package/dist/prosekit-extensions-link.d.ts +0 -1
  77. package/dist/prosekit-extensions-link.d.ts.map +1 -1
  78. package/dist/prosekit-extensions-link.js +4 -4
  79. package/dist/prosekit-extensions-link.js.map +1 -1
  80. package/dist/prosekit-extensions-list.d.ts +0 -1
  81. package/dist/prosekit-extensions-list.d.ts.map +1 -1
  82. package/dist/prosekit-extensions-list.js +3 -3
  83. package/dist/prosekit-extensions-list.js.map +1 -1
  84. package/dist/prosekit-extensions-loro.d.ts +16 -17
  85. package/dist/prosekit-extensions-loro.d.ts.map +1 -1
  86. package/dist/prosekit-extensions-loro.js +14 -7
  87. package/dist/prosekit-extensions-loro.js.map +1 -1
  88. package/dist/prosekit-extensions-mark-rule.d.ts +0 -1
  89. package/dist/prosekit-extensions-mark-rule.d.ts.map +1 -1
  90. package/dist/prosekit-extensions-mark-rule.js +1 -1
  91. package/dist/prosekit-extensions-mention.d.ts.map +1 -1
  92. package/dist/prosekit-extensions-mention.js.map +1 -1
  93. package/dist/prosekit-extensions-mod-click-prevention.d.ts +0 -1
  94. package/dist/prosekit-extensions-mod-click-prevention.d.ts.map +1 -1
  95. package/dist/prosekit-extensions-mod-click-prevention.js.map +1 -1
  96. package/dist/prosekit-extensions-paragraph.d.ts.map +1 -1
  97. package/dist/prosekit-extensions-paragraph.js +1 -1
  98. package/dist/prosekit-extensions-paragraph.js.map +1 -1
  99. package/dist/prosekit-extensions-paste-rule.d.ts +0 -1
  100. package/dist/prosekit-extensions-paste-rule.d.ts.map +1 -1
  101. package/dist/prosekit-extensions-paste-rule.js +1 -1
  102. package/dist/prosekit-extensions-placeholder.d.ts.map +1 -1
  103. package/dist/prosekit-extensions-placeholder.js +3 -4
  104. package/dist/prosekit-extensions-placeholder.js.map +1 -1
  105. package/dist/prosekit-extensions-readonly.d.ts +0 -1
  106. package/dist/prosekit-extensions-readonly.d.ts.map +1 -1
  107. package/dist/prosekit-extensions-readonly.js.map +1 -1
  108. package/dist/prosekit-extensions-search.d.ts +0 -1
  109. package/dist/prosekit-extensions-search.d.ts.map +1 -1
  110. package/dist/prosekit-extensions-search.js.map +1 -1
  111. package/dist/prosekit-extensions-strike.d.ts +0 -1
  112. package/dist/prosekit-extensions-strike.d.ts.map +1 -1
  113. package/dist/prosekit-extensions-strike.js +3 -3
  114. package/dist/prosekit-extensions-strike.js.map +1 -1
  115. package/dist/prosekit-extensions-table.d.ts.map +1 -1
  116. package/dist/prosekit-extensions-table.js +1 -2
  117. package/dist/prosekit-extensions-text-align.d.ts +0 -1
  118. package/dist/prosekit-extensions-text-align.d.ts.map +1 -1
  119. package/dist/prosekit-extensions-text-align.js +6 -6
  120. package/dist/prosekit-extensions-text-align.js.map +1 -1
  121. package/dist/prosekit-extensions-text-color.d.ts +62 -0
  122. package/dist/prosekit-extensions-text-color.d.ts.map +1 -0
  123. package/dist/prosekit-extensions-text-color.js +76 -0
  124. package/dist/prosekit-extensions-text-color.js.map +1 -0
  125. package/dist/prosekit-extensions-text.d.ts +0 -1
  126. package/dist/prosekit-extensions-text.d.ts.map +1 -1
  127. package/dist/prosekit-extensions-text.js.map +1 -1
  128. package/dist/prosekit-extensions-underline.d.ts +0 -1
  129. package/dist/prosekit-extensions-underline.d.ts.map +1 -1
  130. package/dist/prosekit-extensions-virtual-selection.d.ts +0 -1
  131. package/dist/prosekit-extensions-virtual-selection.d.ts.map +1 -1
  132. package/dist/prosekit-extensions-virtual-selection.js.map +1 -1
  133. package/dist/prosekit-extensions-yjs.d.ts +9 -2
  134. package/dist/prosekit-extensions-yjs.d.ts.map +1 -1
  135. package/dist/prosekit-extensions-yjs.js +1 -1
  136. package/dist/prosekit-extensions-yjs.js.map +1 -1
  137. package/dist/{shiki-highlighter-chunk-rkzofy4z.d.ts → shiki-highlighter-chunk-DNNm2Vow.d.ts} +1 -1
  138. package/dist/shiki-highlighter-chunk-DNNm2Vow.d.ts.map +1 -0
  139. package/dist/shiki-highlighter-chunk.d.ts +1 -1
  140. package/dist/shiki-highlighter-chunk.js.map +1 -1
  141. package/dist/{table-BRDh_9mG.js → table-4oHfV-Ql.js} +2 -2
  142. package/dist/table-4oHfV-Ql.js.map +1 -0
  143. package/package.json +33 -18
  144. package/src/autocomplete/autocomplete-helpers.ts +19 -14
  145. package/src/autocomplete/autocomplete-plugin.ts +260 -126
  146. package/src/autocomplete/autocomplete-rule.ts +3 -3
  147. package/src/autocomplete/autocomplete.spec.ts +244 -40
  148. package/src/autocomplete/autocomplete.ts +9 -7
  149. package/src/background-color/background-color-commands.spec.ts +71 -0
  150. package/src/background-color/background-color-commands.ts +35 -0
  151. package/src/background-color/background-color-spec.spec.ts +286 -0
  152. package/src/background-color/background-color-spec.ts +58 -0
  153. package/src/background-color/background-color.ts +21 -0
  154. package/src/background-color/index.ts +8 -0
  155. package/src/blockquote/blockquote-commands.ts +1 -7
  156. package/src/blockquote/blockquote-keymap.spec.ts +5 -9
  157. package/src/blockquote/blockquote-keymap.ts +2 -7
  158. package/src/blockquote/blockquote-spec.ts +1 -4
  159. package/src/blockquote/blockquote.ts +3 -12
  160. package/src/blockquote/index.ts +3 -12
  161. package/src/bold/bold-commands.ts +1 -5
  162. package/src/bold/bold-input-rule.spec.ts +1 -5
  163. package/src/bold/bold-input-rule.ts +1 -4
  164. package/src/bold/bold-keymap.ts +1 -5
  165. package/src/bold/bold-spec.ts +1 -4
  166. package/src/bold/bold.ts +3 -12
  167. package/src/bold/index.ts +3 -12
  168. package/src/code/code-commands.ts +1 -5
  169. package/src/code/code-input-rule.ts +1 -4
  170. package/src/code/code-keymap.ts +1 -5
  171. package/src/code/code-spec.ts +1 -4
  172. package/src/code/code.ts +3 -12
  173. package/src/code/index.ts +3 -12
  174. package/src/code-block/code-block-commands.ts +1 -8
  175. package/src/code-block/code-block-highlight.ts +2 -8
  176. package/src/code-block/code-block-keymap.ts +2 -9
  177. package/src/code-block/code-block-shiki.ts +1 -4
  178. package/src/code-block/code-block-spec.spec.ts +4 -11
  179. package/src/code-block/code-block-spec.ts +1 -4
  180. package/src/code-block/code-block.ts +4 -16
  181. package/src/code-block/index.ts +5 -21
  182. package/src/code-block/shiki-highlighter-chunk.ts +1 -7
  183. package/src/code-block/shiki-highlighter.ts +1 -4
  184. package/src/code-block/shiki-parser.ts +1 -4
  185. package/src/commit/index.ts +7 -36
  186. package/src/doc/index.ts +1 -4
  187. package/src/drop-cursor/drop-cursor.ts +1 -4
  188. package/src/drop-cursor/index.ts +1 -5
  189. package/src/drop-indicator/drop-indicator-facet.ts +12 -21
  190. package/src/drop-indicator/index.ts +1 -5
  191. package/src/enter-rule/index.ts +2 -11
  192. package/src/file/file-paste-handler.spec.ts +3 -16
  193. package/src/file/index.ts +3 -16
  194. package/src/gap-cursor/gap-cursor.ts +1 -4
  195. package/src/gap-cursor/index.ts +1 -4
  196. package/src/hard-break/hard-break-commands.ts +1 -5
  197. package/src/hard-break/hard-break-keymap.spec.ts +6 -12
  198. package/src/hard-break/hard-break-keymap.ts +1 -4
  199. package/src/hard-break/hard-break-spec.ts +1 -4
  200. package/src/hard-break/hard-break.ts +3 -12
  201. package/src/hard-break/index.ts +3 -12
  202. package/src/heading/heading-commands.ts +1 -7
  203. package/src/heading/heading-keymap.spec.ts +8 -12
  204. package/src/heading/heading-keymap.ts +7 -14
  205. package/src/heading/heading-spec.ts +1 -4
  206. package/src/heading/heading.ts +3 -12
  207. package/src/heading/index.ts +3 -12
  208. package/src/horizontal-rule/horizontal-rule-commands.spec.ts +1 -5
  209. package/src/horizontal-rule/horizontal-rule-commands.ts +2 -9
  210. package/src/horizontal-rule/horizontal-rule-input-rule.spec.ts +5 -9
  211. package/src/horizontal-rule/horizontal-rule-input-rule.ts +1 -5
  212. package/src/horizontal-rule/horizontal-rule-spec.ts +1 -4
  213. package/src/horizontal-rule/horizontal-rule.ts +3 -12
  214. package/src/horizontal-rule/index.ts +3 -13
  215. package/src/image/image-commands/upload-image.spec.ts +245 -0
  216. package/src/image/image-commands/upload-image.ts +46 -11
  217. package/src/image/image-commands.ts +2 -8
  218. package/src/image/image-spec.ts +1 -4
  219. package/src/image/image-upload-handler.ts +2 -8
  220. package/src/image/image.ts +3 -12
  221. package/src/image/index.ts +3 -13
  222. package/src/input-rule/index.ts +2 -13
  223. package/src/italic/index.ts +3 -12
  224. package/src/italic/italic-commands.spec.ts +2 -10
  225. package/src/italic/italic-commands.ts +1 -5
  226. package/src/italic/italic-input-rule.spec.ts +1 -5
  227. package/src/italic/italic-input-rule.ts +1 -4
  228. package/src/italic/italic-keymap.ts +1 -5
  229. package/src/italic/italic-spec.ts +1 -4
  230. package/src/italic/italic.ts +3 -12
  231. package/src/link/index.spec.ts +10 -13
  232. package/src/link/index.ts +1 -5
  233. package/src/link/link-paste-rule.spec.ts +2 -9
  234. package/src/link/link-regex.spec.ts +1 -5
  235. package/src/list/index.ts +3 -12
  236. package/src/list/list-commands.ts +1 -5
  237. package/src/list/list-input-rules.ts +1 -4
  238. package/src/list/list-keymap.spec.ts +6 -10
  239. package/src/list/list-keymap.ts +2 -8
  240. package/src/list/list-plugins.ts +1 -4
  241. package/src/list/list-serializer.ts +2 -9
  242. package/src/list/list-spec.ts +3 -13
  243. package/src/list/list.spec.ts +10 -21
  244. package/src/list/list.ts +3 -12
  245. package/src/list/style.css +5 -5
  246. package/src/loro/index.ts +3 -13
  247. package/src/loro/loro-commands.ts +2 -8
  248. package/src/loro/loro-cursor-plugin.ts +21 -21
  249. package/src/loro/loro-keymap.ts +3 -11
  250. package/src/loro/loro-sync-plugin.ts +2 -8
  251. package/src/loro/loro-undo-plugin.ts +2 -8
  252. package/src/loro/loro.ts +16 -21
  253. package/src/mark-rule/apply.ts +3 -13
  254. package/src/mark-rule/mark-rule.spec.ts +2 -13
  255. package/src/mark-rule/mark-rule.ts +2 -13
  256. package/src/mark-rule/range.ts +2 -8
  257. package/src/mark-rule/types.ts +1 -4
  258. package/src/mention/index.ts +1 -8
  259. package/src/mod-click-prevention/index.ts +2 -9
  260. package/src/paragraph/paragraph-commands.ts +1 -5
  261. package/src/paragraph/paragraph-keymap.ts +2 -5
  262. package/src/paragraph/paragraph-spec.ts +1 -4
  263. package/src/paragraph/paragraph.ts +3 -14
  264. package/src/paste-rule/index.ts +2 -10
  265. package/src/paste-rule/mark-paste-rule.spec.ts +3 -13
  266. package/src/paste-rule/mark-paste-rule.ts +4 -14
  267. package/src/paste-rule/paste-rule-plugin.ts +2 -11
  268. package/src/paste-rule/paste-rule.spec.ts +4 -19
  269. package/src/paste-rule/split-text-by-regex.spec.ts +1 -5
  270. package/src/placeholder/index.ts +4 -16
  271. package/src/readonly/index.ts +2 -8
  272. package/src/search/index.ts +1 -6
  273. package/src/strike/index.ts +2 -2
  274. package/src/table/index.ts +10 -40
  275. package/src/table/table-commands/delete-cell-selection.spec.ts +1 -5
  276. package/src/table/table-commands/exit-table.spec.ts +1 -5
  277. package/src/table/table-commands/insert-table.spec.ts +1 -5
  278. package/src/table/table-commands/insert-table.ts +1 -4
  279. package/src/table/table-commands/move-table-column.spec.ts +1 -5
  280. package/src/table/table-commands/move-table-column.ts +1 -4
  281. package/src/table/table-commands/move-table-row.spec.ts +1 -5
  282. package/src/table/table-commands/move-table-row.ts +1 -4
  283. package/src/table/table-commands/select-table-cell.spec.ts +1 -5
  284. package/src/table/table-commands/select-table-column.spec.ts +1 -5
  285. package/src/table/table-commands/select-table-row.spec.ts +1 -5
  286. package/src/table/table-commands/select-table.spec.ts +1 -5
  287. package/src/table/table-commands/select-table.ts +1 -4
  288. package/src/table/table-commands.ts +8 -32
  289. package/src/table/table-plugins.ts +2 -8
  290. package/src/table/table-spec.spec.ts +2 -11
  291. package/src/table/table-spec.ts +2 -8
  292. package/src/table/table-utils.ts +2 -6
  293. package/src/table/table.ts +2 -8
  294. package/src/table/test-utils.ts +1 -4
  295. package/src/testing/clipboard.ts +1 -2
  296. package/src/testing/index.ts +9 -14
  297. package/src/testing/keyboard.ts +0 -30
  298. package/src/text/index.ts +1 -4
  299. package/src/text-align/index.ts +6 -6
  300. package/src/text-color/index.ts +3 -0
  301. package/src/text-color/text-color-commands.spec.ts +71 -0
  302. package/src/text-color/text-color-commands.ts +35 -0
  303. package/src/text-color/text-color-spec.spec.ts +297 -0
  304. package/src/text-color/text-color-spec.ts +58 -0
  305. package/src/text-color/text-color.ts +21 -0
  306. package/src/virtual-selection/index.ts +3 -14
  307. package/src/yjs/index.ts +5 -20
  308. package/src/yjs/yjs-commands.ts +2 -8
  309. package/src/yjs/yjs-cursor-plugin.ts +3 -5
  310. package/src/yjs/yjs-keymap.ts +3 -11
  311. package/src/yjs/yjs-sync-plugin.ts +1 -4
  312. package/src/yjs/yjs-types.ts +10 -0
  313. package/src/yjs/yjs-undo-plugin.ts +2 -8
  314. package/src/yjs/yjs.ts +6 -24
  315. package/dist/drop-indicator-B1QHFb5m.js.map +0 -1
  316. package/dist/enter-rule-CzWOZF_Z.js.map +0 -1
  317. package/dist/file-DrfcSid-.js.map +0 -1
  318. package/dist/index-oIc1a2f2.d.ts.map +0 -1
  319. package/dist/input-rule-dmsb3j6w.js.map +0 -1
  320. package/dist/mark-rule-BcLB4Uv2.js.map +0 -1
  321. package/dist/paste-rule-pVb4sqvJ.js.map +0 -1
  322. package/dist/shiki-highlighter-chunk-rkzofy4z.d.ts.map +0 -1
  323. package/dist/table-BRDh_9mG.js.map +0 -1
  324. package/src/testing/format-html.ts +0 -5
@@ -1,18 +1,9 @@
1
- import {
2
- union,
3
- type Union,
4
- } from '@prosekit/core'
1
+ import { union, type Union } from '@prosekit/core'
5
2
 
6
- import {
7
- defineHeadingCommands,
8
- type HeadingCommandsExtension,
9
- } from './heading-commands'
3
+ import { defineHeadingCommands, type HeadingCommandsExtension } from './heading-commands'
10
4
  import { defineHeadingInputRule } from './heading-input-rule'
11
5
  import { defineHeadingKeymap } from './heading-keymap'
12
- import {
13
- defineHeadingSpec,
14
- type HeadingSpecExtension,
15
- } from './heading-spec'
6
+ import { defineHeadingSpec, type HeadingSpecExtension } from './heading-spec'
16
7
 
17
8
  /**
18
9
  * @internal
@@ -1,15 +1,6 @@
1
- export {
2
- defineHeading,
3
- type HeadingExtension,
4
- } from './heading'
5
- export {
6
- defineHeadingCommands,
7
- type HeadingCommandsExtension,
8
- } from './heading-commands'
1
+ export { defineHeading, type HeadingExtension } from './heading'
2
+ export { defineHeadingCommands, type HeadingCommandsExtension } from './heading-commands'
9
3
  export { defineHeadingInputRule } from './heading-input-rule'
10
4
  export { defineHeadingKeymap } from './heading-keymap'
11
- export {
12
- defineHeadingSpec,
13
- type HeadingSpecExtension,
14
- } from './heading-spec'
5
+ export { defineHeadingSpec, type HeadingSpecExtension } from './heading-spec'
15
6
  export type { HeadingAttrs } from './heading-types'
@@ -1,8 +1,4 @@
1
- import {
2
- describe,
3
- expect,
4
- it,
5
- } from 'vitest'
1
+ import { describe, expect, it } from 'vitest'
6
2
 
7
3
  import { setupTest } from '../testing'
8
4
 
@@ -1,12 +1,5 @@
1
- import {
2
- defineCommands,
3
- getNodeType,
4
- type Extension,
5
- } from '@prosekit/core'
6
- import {
7
- Fragment,
8
- Slice,
9
- } from '@prosekit/pm/model'
1
+ import { defineCommands, getNodeType, type Extension } from '@prosekit/core'
2
+ import { Fragment, Slice } from '@prosekit/pm/model'
10
3
  import type { Command } from '@prosekit/pm/state'
11
4
 
12
5
  export type HorizontalRuleCommandsExtension = Extension<{
@@ -1,15 +1,11 @@
1
- import {
2
- describe,
3
- expect,
4
- it,
5
- } from 'vitest'
1
+ import { describe, expect, it } from 'vitest'
6
2
 
7
3
  import { setupTest } from '../testing'
8
4
  import { inputText } from '../testing/keyboard'
9
5
 
10
6
  describe('defineHorizontalRuleInputRule', () => {
11
7
  const { editor, n } = setupTest()
12
- it('should insert a horizontal rule when typing "---" in an empty paragraph', async () => {
8
+ it('should insert when typing "---" in an empty paragraph', async () => {
13
9
  const doc = n.doc(n.p('<a>'))
14
10
  editor.set(doc)
15
11
 
@@ -24,7 +20,7 @@ describe('defineHorizontalRuleInputRule', () => {
24
20
  )
25
21
  })
26
22
 
27
- it('should insert a horizontal rule when typing "---" before some text', async () => {
23
+ it('should insert when typing "---" before some text', async () => {
28
24
  const doc = n.doc(n.p('<a>123'))
29
25
  editor.set(doc)
30
26
 
@@ -39,7 +35,7 @@ describe('defineHorizontalRuleInputRule', () => {
39
35
  )
40
36
  })
41
37
 
42
- it('should not insert a horizontal rule when typing "---" after some text', async () => {
38
+ it('should not insert when typing "---" after some text', async () => {
43
39
  const doc = n.doc(n.p('123<a>'))
44
40
  editor.set(doc)
45
41
 
@@ -49,7 +45,7 @@ describe('defineHorizontalRuleInputRule', () => {
49
45
  )
50
46
  })
51
47
 
52
- it('should not insert a horizontal rule inside a code block', async () => {
48
+ it('should not insert inside a code block', async () => {
53
49
  const doc = n.doc(n.codeBlock('<a>'))
54
50
  editor.set(doc)
55
51
 
@@ -1,8 +1,4 @@
1
- import {
2
- getNodeType,
3
- union,
4
- type PlainExtension,
5
- } from '@prosekit/core'
1
+ import { getNodeType, union, type PlainExtension } from '@prosekit/core'
6
2
  import { InputRule } from '@prosekit/pm/inputrules'
7
3
 
8
4
  import { defineInputRule } from '../input-rule'
@@ -1,7 +1,4 @@
1
- import {
2
- defineNodeSpec,
3
- type Extension,
4
- } from '@prosekit/core'
1
+ import { defineNodeSpec, type Extension } from '@prosekit/core'
5
2
  import type { Attrs } from '@prosekit/pm/model'
6
3
 
7
4
  export type HorizontalRuleSpecExtension = Extension<{
@@ -1,17 +1,8 @@
1
- import {
2
- union,
3
- type Union,
4
- } from '@prosekit/core'
1
+ import { union, type Union } from '@prosekit/core'
5
2
 
6
- import {
7
- defineHorizontalRuleCommands,
8
- type HorizontalRuleCommandsExtension,
9
- } from './horizontal-rule-commands'
3
+ import { defineHorizontalRuleCommands, type HorizontalRuleCommandsExtension } from './horizontal-rule-commands'
10
4
  import { defineHorizontalRuleInputRule } from './horizontal-rule-input-rule'
11
- import {
12
- defineHorizontalRuleSpec,
13
- type HorizontalRuleSpecExtension,
14
- } from './horizontal-rule-spec'
5
+ import { defineHorizontalRuleSpec, type HorizontalRuleSpecExtension } from './horizontal-rule-spec'
15
6
 
16
7
  export type HorizontalRuleExtension = Union<
17
8
  [HorizontalRuleSpecExtension, HorizontalRuleCommandsExtension]
@@ -1,14 +1,4 @@
1
- export {
2
- defineHorizontalRule,
3
- type HorizontalRuleExtension,
4
- } from './horizontal-rule'
5
- export {
6
- defineHorizontalRuleCommands,
7
- insertHorizontalRule,
8
- type HorizontalRuleCommandsExtension,
9
- } from './horizontal-rule-commands'
1
+ export { defineHorizontalRule, type HorizontalRuleExtension } from './horizontal-rule'
2
+ export { defineHorizontalRuleCommands, insertHorizontalRule, type HorizontalRuleCommandsExtension } from './horizontal-rule-commands'
10
3
  export { defineHorizontalRuleInputRule } from './horizontal-rule-input-rule'
11
- export {
12
- defineHorizontalRuleSpec,
13
- type HorizontalRuleSpecExtension,
14
- } from './horizontal-rule-spec'
4
+ export { defineHorizontalRuleSpec, type HorizontalRuleSpecExtension } from './horizontal-rule-spec'
@@ -0,0 +1,245 @@
1
+ import { sleep } from '@ocavue/utils'
2
+ import { findNode, findNodes } from '@prosekit/core'
3
+ import type { ProseMirrorNode } from '@prosekit/pm/model'
4
+ import { describe, expect, it, vi } from 'vitest'
5
+
6
+ import type { Uploader } from '../../file'
7
+ import { setupTest } from '../../testing'
8
+ import type { ImageAttrs } from '../image-spec'
9
+
10
+ import { replaceImageURL, uploadImage, type ImageUploadErrorHandler } from './upload-image'
11
+
12
+ describe('uploadImage', () => {
13
+ it('should insert image at current selection by default', async () => {
14
+ const { editor, n, mockUploader, file, findImage } = setup()
15
+ const doc = n.doc(n.paragraph('hello'))
16
+ editor.set(doc)
17
+ editor.view.dispatch(editor.state.tr.setSelection(editor.state.selection))
18
+
19
+ const command = uploadImage({ uploader: mockUploader, file })
20
+ expect(editor.exec(command)).toBe(true)
21
+
22
+ expect(findImage().attrs.src).toMatch(/^blob:/)
23
+ await sleep(0)
24
+ expect(findImage().attrs.src).toBe('https://example.com/uploaded.png')
25
+ })
26
+
27
+ it('should insert image at specified position', async () => {
28
+ const { editor, n, mockUploader, file, findImage } = setup()
29
+ const doc = n.doc(
30
+ /*0*/
31
+ n.paragraph(/*1*/ 'hello' /*6*/),
32
+ /*7*/
33
+ n.paragraph(/*8*/ 'world' /*13*/),
34
+ /*14*/
35
+ )
36
+ editor.set(doc)
37
+
38
+ const imagePos = 7
39
+ const command = uploadImage({ uploader: mockUploader, file, pos: imagePos })
40
+ expect(editor.exec(command)).toBe(true)
41
+
42
+ expect(findImage().attrs.src).toMatch(/^blob:/)
43
+ await sleep(0)
44
+ expect(findImage().attrs.src).toBe('https://example.com/uploaded.png')
45
+ })
46
+
47
+ it('should replace existing image when replace=true', async () => {
48
+ const { editor, n, mockUploader, file, findImageURLs } = setup()
49
+ const doc = n.doc(
50
+ /*0*/
51
+ n.paragraph(/*1*/ 'hello' /*6*/),
52
+ /*7*/
53
+ n.image({ src: 'https://example.com/old.png' }),
54
+ /*8*/
55
+ n.paragraph(/*9*/ 'world' /*14*/),
56
+ /*15*/
57
+ )
58
+ editor.set(doc)
59
+ expect(findImageURLs()).toEqual(['https://example.com/old.png'])
60
+
61
+ const imagePos = 7
62
+ const command = uploadImage({
63
+ uploader: mockUploader,
64
+ file,
65
+ pos: imagePos,
66
+ replace: true,
67
+ })
68
+ expect(editor.exec(command)).toBe(true)
69
+
70
+ await sleep(0)
71
+ expect(findImageURLs()).toEqual(['https://example.com/uploaded.png'])
72
+ })
73
+
74
+ it('should not replace existing image when replace=false', async () => {
75
+ const { editor, n, mockUploader, file, findImageURLs } = setup()
76
+ const doc = n.doc(
77
+ /*0*/
78
+ n.paragraph(/*1*/ 'hello' /*6*/),
79
+ /*7*/
80
+ n.image({ src: 'https://example.com/old.png' }),
81
+ /*8*/
82
+ n.paragraph(/*9*/ 'world' /*14*/),
83
+ /*15*/
84
+ )
85
+ editor.set(doc)
86
+ expect(findImageURLs()).toEqual(['https://example.com/old.png'])
87
+
88
+ const imagePos = 7
89
+ const command = uploadImage({
90
+ uploader: mockUploader,
91
+ file,
92
+ pos: imagePos,
93
+ replace: false,
94
+ })
95
+ expect(editor.exec(command)).toBe(true)
96
+ await sleep(0)
97
+ expect(findImageURLs()).toEqual(['https://example.com/uploaded.png', 'https://example.com/old.png'])
98
+ })
99
+
100
+ it('should insert image when replace=true but position has non-image node', async () => {
101
+ const { editor, n, mockUploader, file, findImageURLs } = setup()
102
+ const doc = n.doc(
103
+ /*0*/
104
+ n.paragraph(/*1*/ 'hello' /*6*/),
105
+ /*7*/
106
+ n.paragraph(/*8*/ 'world' /*13*/),
107
+ /*14*/
108
+ )
109
+ editor.set(doc)
110
+
111
+ const command = uploadImage({
112
+ uploader: mockUploader,
113
+ file,
114
+ pos: 11,
115
+ replace: true,
116
+ })
117
+ expect(editor.exec(command)).toBe(true)
118
+ expect(editor.state.doc.child(0).type.name).toBe('paragraph')
119
+ expect(editor.state.doc.child(1).type.name).toBe('paragraph')
120
+ expect(editor.state.doc.child(2).type.name).toBe('image')
121
+ await sleep(0)
122
+ expect(findImageURLs()).toEqual(['https://example.com/uploaded.png'])
123
+ })
124
+
125
+ it('should call onError when upload fails', async () => {
126
+ const { editor, n, file } = setup()
127
+ const error = new Error('Upload failed')
128
+ const failingUploader: Uploader<string> = vi.fn().mockRejectedValue(error)
129
+ const onError = vi.fn<ImageUploadErrorHandler>()
130
+
131
+ const doc = n.doc(n.paragraph('hello'))
132
+ editor.set(doc)
133
+
134
+ const command = uploadImage({
135
+ uploader: failingUploader,
136
+ file,
137
+ onError,
138
+ })
139
+ editor.exec(command)
140
+
141
+ await sleep(0)
142
+ expect(onError).toHaveBeenCalledOnce()
143
+ const callArg = onError.mock.calls[0][0]
144
+ expect(callArg.file).toBe(file)
145
+ expect(callArg.uploadTask).toBeDefined()
146
+ expect((callArg.error as Error).cause).toBe(error)
147
+ })
148
+ })
149
+
150
+ describe('replaceImageURL', () => {
151
+ it('should replace single image URL', () => {
152
+ const { editor, n, findImage } = setup()
153
+ const doc = n.doc(
154
+ n.paragraph('hello'),
155
+ n.image({ src: 'blob:old-url' }),
156
+ n.paragraph('world'),
157
+ )
158
+ editor.set(doc)
159
+
160
+ replaceImageURL(editor.view, 'blob:old-url', 'https://example.com/new.png')
161
+
162
+ expect(findImage().attrs.src).toBe('https://example.com/new.png')
163
+ })
164
+
165
+ it('should replace multiple image URLs', () => {
166
+ const { editor, n, findImageURLs } = setup()
167
+ const doc = n.doc(
168
+ n.paragraph('hello'),
169
+ n.image({ src: 'blob:old-url' }),
170
+ n.paragraph('middle'),
171
+ n.image({ src: 'blob:old-url' }),
172
+ n.paragraph('world'),
173
+ )
174
+ editor.set(doc)
175
+
176
+ replaceImageURL(editor.view, 'blob:old-url', 'https://example.com/new.png')
177
+
178
+ expect(findImageURLs()).toEqual(['https://example.com/new.png', 'https://example.com/new.png'])
179
+ })
180
+
181
+ it('should not replace images with different URLs', () => {
182
+ const { editor, n, findImageURLs } = setup()
183
+ const doc = n.doc(
184
+ n.paragraph('hello'),
185
+ n.image({ src: 'blob:old-url' }),
186
+ n.image({ src: 'blob:different-url' }),
187
+ n.paragraph('world'),
188
+ )
189
+ editor.set(doc)
190
+
191
+ replaceImageURL(editor.view, 'blob:old-url', 'https://example.com/new.png')
192
+
193
+ expect(findImageURLs()).toEqual(['https://example.com/new.png', 'blob:different-url'])
194
+ })
195
+
196
+ it('should do nothing when no images match', () => {
197
+ const { editor, n } = setup()
198
+ const doc = n.doc(
199
+ n.paragraph('hello'),
200
+ n.image({ src: 'blob:different-url' }),
201
+ n.paragraph('world'),
202
+ )
203
+ editor.set(doc)
204
+
205
+ const initialState = editor.state
206
+
207
+ replaceImageURL(editor.view, 'blob:non-existent', 'https://example.com/new.png')
208
+
209
+ expect(editor.state).toBe(initialState)
210
+ })
211
+ })
212
+
213
+ function isImage(node: ProseMirrorNode) {
214
+ return node.type.name === 'image'
215
+ }
216
+
217
+ function setup() {
218
+ const { editor, n } = setupTest()
219
+ const mockUploader = vi.fn().mockResolvedValue('https://example.com/uploaded.png')
220
+ const file = new File(['test'], 'test.png', { type: 'image/png' })
221
+
222
+ const findImage = (): {
223
+ pos: number
224
+ attrs: ImageAttrs
225
+ node: ProseMirrorNode
226
+ } => {
227
+ const found = findNode(editor.state.doc, isImage)
228
+ if (!found) {
229
+ throw new Error('Image not found')
230
+ }
231
+ const { pos, node } = found
232
+ const attrs = node.attrs as ImageAttrs
233
+ return { pos, attrs, node }
234
+ }
235
+
236
+ const findImages = () => {
237
+ return findNodes(editor.state.doc, isImage)
238
+ }
239
+
240
+ const findImageURLs = (): string[] => {
241
+ return findImages().map(({ node }) => (node.attrs as ImageAttrs).src || '')
242
+ }
243
+
244
+ return { editor, n, mockUploader, file, findImage, findImageURLs }
245
+ }
@@ -1,14 +1,8 @@
1
- import {
2
- insertNode,
3
- ProseKitError,
4
- } from '@prosekit/core'
5
- import type { Command } from '@prosekit/pm/state'
1
+ import { insertNode, ProseKitError } from '@prosekit/core'
2
+ import type { Command, EditorState, Transaction } from '@prosekit/pm/state'
6
3
  import type { EditorView } from '@prosekit/pm/view'
7
4
 
8
- import {
9
- UploadTask,
10
- type Uploader,
11
- } from '../../file'
5
+ import { UploadTask, type Uploader } from '../../file'
12
6
  import type { ImageAttrs } from '../image-spec'
13
7
 
14
8
  /**
@@ -31,6 +25,13 @@ export interface UploadImageOptions {
31
25
  * image is inserted at the current selection.
32
26
  */
33
27
  pos?: number
28
+ /**
29
+ * If the image should replace the existing image at the given position. This
30
+ * is only used if `pos` is provided.
31
+ *
32
+ * @default false
33
+ */
34
+ replace?: boolean
34
35
  /**
35
36
  * A handler to be called when an error occurs during the upload.
36
37
  */
@@ -72,11 +73,16 @@ export type ImageUploadErrorHandler = (options: ImageUploadErrorHandlerOptions)
72
73
  *
73
74
  * @public
74
75
  */
75
- export function uploadImage({ uploader, file, pos, onError }: UploadImageOptions): Command {
76
+ export function uploadImage({
77
+ uploader,
78
+ file,
79
+ pos,
80
+ replace = false,
81
+ onError,
82
+ }: UploadImageOptions): Command {
76
83
  return (state, dispatch, view) => {
77
84
  const uploadTask = new UploadTask({ file, uploader })
78
85
  const objectURL = uploadTask.objectURL
79
- const attrs: ImageAttrs = { src: objectURL }
80
86
 
81
87
  uploadTask.finished
82
88
  .then((resultURL) => {
@@ -101,10 +107,39 @@ export function uploadImage({ uploader, file, pos, onError }: UploadImageOptions
101
107
  onError?.({ file, error, uploadTask })
102
108
  })
103
109
 
110
+ if (replace && pos != null) {
111
+ if (replaceExistingImageURL(state, pos, objectURL, dispatch)) {
112
+ return true
113
+ }
114
+ }
115
+
116
+ const attrs: ImageAttrs = { src: objectURL }
104
117
  return insertNode({ type: 'image', attrs, pos })(state, dispatch, view)
105
118
  }
106
119
  }
107
120
 
121
+ function replaceExistingImageURL(
122
+ state: EditorState,
123
+ pos: number,
124
+ imageURL: string,
125
+ dispatch?: (tr: Transaction) => void,
126
+ ): boolean {
127
+ const node = state.doc.nodeAt(pos)
128
+ if (!node || node.type.name !== 'image') {
129
+ return false
130
+ }
131
+ const attrs = node.attrs as ImageAttrs
132
+ if (attrs.src === imageURL) {
133
+ return true
134
+ }
135
+ if (dispatch) {
136
+ const tr = state.tr
137
+ tr.setNodeAttribute(pos, 'src', imageURL)
138
+ dispatch(tr)
139
+ }
140
+ return true
141
+ }
142
+
108
143
  /**
109
144
  * Replaces the temporary image URL with the final uploaded URL.
110
145
  *
@@ -1,13 +1,7 @@
1
- import {
2
- defineCommands,
3
- type Extension,
4
- } from '@prosekit/core'
1
+ import { defineCommands, type Extension } from '@prosekit/core'
5
2
 
6
3
  import { insertImage } from './image-commands/insert-image'
7
- import {
8
- uploadImage,
9
- type UploadImageOptions,
10
- } from './image-commands/upload-image'
4
+ import { uploadImage, type UploadImageOptions } from './image-commands/upload-image'
11
5
  import type { ImageAttrs } from './image-spec'
12
6
 
13
7
  /**
@@ -1,7 +1,4 @@
1
- import {
2
- defineNodeSpec,
3
- type Extension,
4
- } from '@prosekit/core'
1
+ import { defineNodeSpec, type Extension } from '@prosekit/core'
5
2
 
6
3
  /**
7
4
  * @public
@@ -1,7 +1,4 @@
1
- import {
2
- union,
3
- type PlainExtension,
4
- } from '@prosekit/core'
1
+ import { union, type PlainExtension } from '@prosekit/core'
5
2
 
6
3
  import {
7
4
  defineFileDropHandler,
@@ -13,10 +10,7 @@ import {
13
10
  type Uploader,
14
11
  } from '../file'
15
12
 
16
- import {
17
- uploadImage,
18
- type ImageUploadErrorHandler,
19
- } from './image-commands/upload-image'
13
+ import { uploadImage, type ImageUploadErrorHandler } from './image-commands/upload-image'
20
14
 
21
15
  /**
22
16
  * A predicate to determine if the pasted file should be uploaded and inserted as an image.
@@ -1,16 +1,7 @@
1
- import {
2
- union,
3
- type Union,
4
- } from '@prosekit/core'
1
+ import { union, type Union } from '@prosekit/core'
5
2
 
6
- import {
7
- defineImageCommands,
8
- type ImageCommandsExtension,
9
- } from './image-commands'
10
- import {
11
- defineImageSpec,
12
- type ImageSpecExtension,
13
- } from './image-spec'
3
+ import { defineImageCommands, type ImageCommandsExtension } from './image-commands'
4
+ import { defineImageSpec, type ImageSpecExtension } from './image-spec'
14
5
 
15
6
  /**
16
7
  * @internal
@@ -1,11 +1,5 @@
1
- export {
2
- defineImage,
3
- type ImageExtension,
4
- } from './image'
5
- export {
6
- defineImageCommands,
7
- type ImageCommandsExtension,
8
- } from './image-commands'
1
+ export { defineImage, type ImageExtension } from './image'
2
+ export { defineImageCommands, type ImageCommandsExtension } from './image-commands'
9
3
  export { insertImage } from './image-commands/insert-image'
10
4
  export {
11
5
  replaceImageURL,
@@ -14,11 +8,7 @@ export {
14
8
  type ImageUploadErrorHandlerOptions,
15
9
  type UploadImageOptions,
16
10
  } from './image-commands/upload-image'
17
- export {
18
- defineImageSpec,
19
- type ImageAttrs,
20
- type ImageSpecExtension,
21
- } from './image-spec'
11
+ export { defineImageSpec, type ImageAttrs, type ImageSpecExtension } from './image-spec'
22
12
  export {
23
13
  defineImageUploadHandler,
24
14
  type ImageCanDropPredicate,
@@ -9,19 +9,8 @@ import {
9
9
  type PlainExtension,
10
10
  type PluginPayload,
11
11
  } from '@prosekit/core'
12
- import {
13
- InputRule,
14
- inputRules,
15
- textblockTypeInputRule,
16
- wrappingInputRule,
17
- } from '@prosekit/pm/inputrules'
18
- import type {
19
- Attrs,
20
- MarkType,
21
- NodeType,
22
- ProseMirrorNode,
23
- Schema,
24
- } from '@prosekit/pm/model'
12
+ import { InputRule, inputRules, textblockTypeInputRule, wrappingInputRule } from '@prosekit/pm/inputrules'
13
+ import type { Attrs, MarkType, NodeType, ProseMirrorNode, Schema } from '@prosekit/pm/model'
25
14
  import type { Plugin } from '@prosekit/pm/state'
26
15
 
27
16
  /**
@@ -1,14 +1,5 @@
1
- export {
2
- defineItalic,
3
- type ItalicExtension,
4
- } from './italic'
5
- export {
6
- defineItalicCommands,
7
- type ItalicCommandsExtension,
8
- } from './italic-commands'
1
+ export { defineItalic, type ItalicExtension } from './italic'
2
+ export { defineItalicCommands, type ItalicCommandsExtension } from './italic-commands'
9
3
  export { defineItalicInputRule } from './italic-input-rule'
10
4
  export { defineItalicKeymap } from './italic-keymap'
11
- export {
12
- defineItalicSpec,
13
- type ItalicSpecExtension,
14
- } from './italic-spec'
5
+ export { defineItalicSpec, type ItalicSpecExtension } from './italic-spec'
@@ -1,13 +1,5 @@
1
- import {
2
- createEditor,
3
- defineBaseCommands,
4
- union,
5
- } from '@prosekit/core'
6
- import {
7
- describe,
8
- expect,
9
- it,
10
- } from 'vitest'
1
+ import { createEditor, defineBaseCommands, union } from '@prosekit/core'
2
+ import { describe, expect, it } from 'vitest'
11
3
 
12
4
  import { defineDoc } from '../doc'
13
5
  import { defineParagraph } from '../paragraph'
@@ -1,8 +1,4 @@
1
- import {
2
- defineCommands,
3
- toggleMark,
4
- type Extension,
5
- } from '@prosekit/core'
1
+ import { defineCommands, toggleMark, type Extension } from '@prosekit/core'
6
2
 
7
3
  /**
8
4
  * @internal