@meta-1/editor 0.0.29 → 1.0.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 (502) hide show
  1. package/package.json +52 -67
  2. package/src/components/notion-like/notion-like-editor-toolbar-floating.tsx +181 -0
  3. package/src/components/tiptap-extension/list-normalization-extension.ts +112 -0
  4. package/src/components/tiptap-extension/node-alignment-extension.ts +285 -0
  5. package/src/components/tiptap-extension/node-background-extension.ts +150 -0
  6. package/src/components/tiptap-extension/ui-state-extension.ts +97 -0
  7. package/src/components/tiptap-icons/add-col-left-icon.tsx +30 -0
  8. package/src/components/tiptap-icons/add-col-right-icon.tsx +30 -0
  9. package/src/components/tiptap-icons/add-row-bottom-icon.tsx +30 -0
  10. package/src/components/tiptap-icons/add-row-top-icon.tsx +30 -0
  11. package/src/components/tiptap-icons/ai-sparkles-icon.tsx +32 -0
  12. package/src/components/tiptap-icons/align-bottom-icon.tsx +28 -0
  13. package/src/components/tiptap-icons/align-center-icon.tsx +38 -0
  14. package/src/components/tiptap-icons/align-center-vertical-icon.tsx +34 -0
  15. package/src/components/tiptap-icons/align-end-vertical-icon.tsx +34 -0
  16. package/src/components/tiptap-icons/align-justify-icon.tsx +38 -0
  17. package/src/components/tiptap-icons/align-left-icon.tsx +38 -0
  18. package/src/components/tiptap-icons/align-middle-icon.tsx +55 -0
  19. package/src/components/tiptap-icons/align-right-icon.tsx +38 -0
  20. package/src/components/tiptap-icons/align-start-vertical-icon.tsx +32 -0
  21. package/src/components/tiptap-icons/align-top-icon.tsx +28 -0
  22. package/src/components/tiptap-icons/alignment-icon.tsx +72 -0
  23. package/src/components/tiptap-icons/arrow-down-a-z-icon.tsx +34 -0
  24. package/src/components/tiptap-icons/arrow-down-icon.tsx +24 -0
  25. package/src/components/tiptap-icons/arrow-down-to-line-icon.tsx +28 -0
  26. package/src/components/tiptap-icons/arrow-down-z-a-icon.tsx +34 -0
  27. package/src/components/tiptap-icons/arrow-left-icon.tsx +24 -0
  28. package/src/components/tiptap-icons/arrow-right-icon.tsx +26 -0
  29. package/src/components/tiptap-icons/arrow-up-icon.tsx +26 -0
  30. package/src/components/tiptap-icons/at-sign-icon.tsx +26 -0
  31. package/src/components/tiptap-icons/ban-icon.tsx +26 -0
  32. package/src/components/tiptap-icons/blockquote-icon.tsx +44 -0
  33. package/src/components/tiptap-icons/bold-icon.tsx +26 -0
  34. package/src/components/tiptap-icons/check-ai-icon.tsx +32 -0
  35. package/src/components/tiptap-icons/check-icon.tsx +26 -0
  36. package/src/components/tiptap-icons/chevron-down-icon.tsx +26 -0
  37. package/src/components/tiptap-icons/chevron-right-icon.tsx +26 -0
  38. package/src/components/tiptap-icons/clipboard-icon.tsx +24 -0
  39. package/src/components/tiptap-icons/close-icon.tsx +24 -0
  40. package/src/components/tiptap-icons/code-block-icon.tsx +38 -0
  41. package/src/components/tiptap-icons/code2-icon.tsx +32 -0
  42. package/src/components/tiptap-icons/complete-sentence-icon.tsx +44 -0
  43. package/src/components/tiptap-icons/copy-icon.tsx +32 -0
  44. package/src/components/tiptap-icons/corner-down-left-icon.tsx +26 -0
  45. package/src/components/tiptap-icons/external-link-icon.tsx +28 -0
  46. package/src/components/tiptap-icons/grip-4-icon.tsx +24 -0
  47. package/src/components/tiptap-icons/grip-vertical-icon.tsx +44 -0
  48. package/src/components/tiptap-icons/heading-five-icon.tsx +28 -0
  49. package/src/components/tiptap-icons/heading-four-icon.tsx +28 -0
  50. package/src/components/tiptap-icons/heading-one-icon.tsx +28 -0
  51. package/src/components/tiptap-icons/heading-six-icon.tsx +30 -0
  52. package/src/components/tiptap-icons/heading-three-icon.tsx +36 -0
  53. package/src/components/tiptap-icons/heading-two-icon.tsx +28 -0
  54. package/src/components/tiptap-icons/highlighter-icon.tsx +26 -0
  55. package/src/components/tiptap-icons/image-caption-icon.tsx +38 -0
  56. package/src/components/tiptap-icons/image-icon.tsx +26 -0
  57. package/src/components/tiptap-icons/image-plus-icon.tsx +26 -0
  58. package/src/components/tiptap-icons/italic-icon.tsx +24 -0
  59. package/src/components/tiptap-icons/languages-icon.tsx +34 -0
  60. package/src/components/tiptap-icons/link-icon.tsx +28 -0
  61. package/src/components/tiptap-icons/list-icon.tsx +56 -0
  62. package/src/components/tiptap-icons/list-ordered-icon.tsx +56 -0
  63. package/src/components/tiptap-icons/list-todo-icon.tsx +50 -0
  64. package/src/components/tiptap-icons/message-square-icon.tsx +26 -0
  65. package/src/components/tiptap-icons/message-square-plus-icon.tsx +32 -0
  66. package/src/components/tiptap-icons/mic-ai-icon.tsx +34 -0
  67. package/src/components/tiptap-icons/minus-icon.tsx +26 -0
  68. package/src/components/tiptap-icons/moon-star-icon.tsx +30 -0
  69. package/src/components/tiptap-icons/more-vertical-icon.tsx +38 -0
  70. package/src/components/tiptap-icons/move-horizontal-icon.tsx +24 -0
  71. package/src/components/tiptap-icons/paint-bucket-icon.tsx +32 -0
  72. package/src/components/tiptap-icons/plus-icon.tsx +24 -0
  73. package/src/components/tiptap-icons/plus-small-icon.tsx +24 -0
  74. package/src/components/tiptap-icons/redo2-icon.tsx +26 -0
  75. package/src/components/tiptap-icons/refresh-ai-icon.tsx +34 -0
  76. package/src/components/tiptap-icons/refresh-ccw-icon.tsx +28 -0
  77. package/src/components/tiptap-icons/repeat-2-icon.tsx +26 -0
  78. package/src/components/tiptap-icons/rotate-ccw-icon.tsx +24 -0
  79. package/src/components/tiptap-icons/simplify-2-icon.tsx +24 -0
  80. package/src/components/tiptap-icons/smile-ai-icon.tsx +38 -0
  81. package/src/components/tiptap-icons/smile-plus-icon.tsx +26 -0
  82. package/src/components/tiptap-icons/square-x-icon.tsx +26 -0
  83. package/src/components/tiptap-icons/stop-circle-2-icon.tsx +26 -0
  84. package/src/components/tiptap-icons/strike-icon.tsx +28 -0
  85. package/src/components/tiptap-icons/subscript-icon.tsx +38 -0
  86. package/src/components/tiptap-icons/summarize-text-icon.tsx +36 -0
  87. package/src/components/tiptap-icons/sun-icon.tsx +58 -0
  88. package/src/components/tiptap-icons/superscript-icon.tsx +38 -0
  89. package/src/components/tiptap-icons/table-cell-merge-icon.tsx +44 -0
  90. package/src/components/tiptap-icons/table-cell-split-icon.tsx +44 -0
  91. package/src/components/tiptap-icons/table-column-icon.tsx +26 -0
  92. package/src/components/tiptap-icons/table-header-column-icon.tsx +28 -0
  93. package/src/components/tiptap-icons/table-header-row-icon.tsx +26 -0
  94. package/src/components/tiptap-icons/table-icon.tsx +26 -0
  95. package/src/components/tiptap-icons/table-row-icon.tsx +26 -0
  96. package/src/components/tiptap-icons/text-color-small-icon.tsx +26 -0
  97. package/src/components/tiptap-icons/text-extend-icon.tsx +36 -0
  98. package/src/components/tiptap-icons/text-reduce-icon.tsx +32 -0
  99. package/src/components/tiptap-icons/trash-icon.tsx +26 -0
  100. package/src/components/tiptap-icons/type-icon.tsx +24 -0
  101. package/src/components/tiptap-icons/underline-icon.tsx +26 -0
  102. package/src/components/tiptap-icons/undo2-icon.tsx +26 -0
  103. package/src/components/tiptap-icons/x-icon.tsx +24 -0
  104. package/src/components/tiptap-node/blockquote-node/blockquote-node.css +18 -0
  105. package/src/components/tiptap-node/code-block-node/code-block-node.css +24 -0
  106. package/src/components/tiptap-node/heading-node/heading-node.css +33 -0
  107. package/src/components/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension.ts +11 -0
  108. package/src/components/tiptap-node/horizontal-rule-node/horizontal-rule-node.css +12 -0
  109. package/src/components/tiptap-node/image-node/image-node-extension.ts +169 -0
  110. package/src/components/tiptap-node/image-node/image-node-floating.tsx +41 -0
  111. package/src/components/tiptap-node/image-node/image-node-view.css +60 -0
  112. package/src/components/tiptap-node/image-node/image-node-view.tsx +316 -0
  113. package/src/components/tiptap-node/image-node/image-node.css +28 -0
  114. package/src/components/tiptap-node/image-upload-node/image-upload-node-extension.ts +155 -0
  115. package/src/components/tiptap-node/image-upload-node/image-upload-node.css +141 -0
  116. package/src/components/tiptap-node/image-upload-node/image-upload-node.tsx +513 -0
  117. package/src/components/tiptap-node/image-upload-node/index.tsx +1 -0
  118. package/src/components/tiptap-node/list-node/list-node.css +127 -0
  119. package/src/components/tiptap-node/paragraph-node/paragraph-node.css +198 -0
  120. package/src/components/tiptap-node/table-node/extensions/table-handle/helpers/create-image.ts +273 -0
  121. package/src/components/tiptap-node/table-node/extensions/table-handle/index.ts +2 -0
  122. package/src/components/tiptap-node/table-node/extensions/table-handle/table-handle-plugin.ts +718 -0
  123. package/src/components/tiptap-node/table-node/extensions/table-handle/table-handle.ts +48 -0
  124. package/src/components/tiptap-node/table-node/extensions/table-node-extension.ts +226 -0
  125. package/src/components/tiptap-node/table-node/hooks/use-table-handle-state.ts +66 -0
  126. package/src/components/tiptap-node/table-node/lib/tiptap-table-utils.ts +1289 -0
  127. package/src/components/tiptap-node/table-node/styles/prosemirror-table.css +35 -0
  128. package/src/components/tiptap-node/table-node/styles/table-node.css +158 -0
  129. package/src/components/tiptap-node/table-node/ui/table-add-row-column-button/index.tsx +2 -0
  130. package/src/components/tiptap-node/table-node/ui/table-add-row-column-button/table-add-row-column-button.tsx +94 -0
  131. package/src/components/tiptap-node/table-node/ui/table-add-row-column-button/use-table-add-row-column.ts +325 -0
  132. package/src/components/tiptap-node/table-node/ui/table-align-cell-button/index.tsx +2 -0
  133. package/src/components/tiptap-node/table-node/ui/table-align-cell-button/table-align-cell-button.tsx +129 -0
  134. package/src/components/tiptap-node/table-node/ui/table-align-cell-button/use-table-align-cell.ts +528 -0
  135. package/src/components/tiptap-node/table-node/ui/table-alignment-menu/index.tsx +1 -0
  136. package/src/components/tiptap-node/table-node/ui/table-alignment-menu/table-alignment-menu.tsx +154 -0
  137. package/src/components/tiptap-node/table-node/ui/table-cell-handle-menu/index.tsx +1 -0
  138. package/src/components/tiptap-node/table-node/ui/table-cell-handle-menu/table-cell-handle-menu.css +62 -0
  139. package/src/components/tiptap-node/table-node/ui/table-cell-handle-menu/table-cell-handle-menu.tsx +212 -0
  140. package/src/components/tiptap-node/table-node/ui/table-clear-row-column-content-button/index.tsx +2 -0
  141. package/src/components/tiptap-node/table-node/ui/table-clear-row-column-content-button/table-clear-row-column-content-button.tsx +101 -0
  142. package/src/components/tiptap-node/table-node/ui/table-clear-row-column-content-button/use-table-clear-row-column-content.ts +423 -0
  143. package/src/components/tiptap-node/table-node/ui/table-delete-row-column-button/index.tsx +2 -0
  144. package/src/components/tiptap-node/table-node/ui/table-delete-row-column-button/table-delete-row-column-button.tsx +100 -0
  145. package/src/components/tiptap-node/table-node/ui/table-delete-row-column-button/use-table-delete-row-column.ts +243 -0
  146. package/src/components/tiptap-node/table-node/ui/table-duplicate-row-column-button/index.tsx +2 -0
  147. package/src/components/tiptap-node/table-node/ui/table-duplicate-row-column-button/table-duplicate-row-column-button.tsx +92 -0
  148. package/src/components/tiptap-node/table-node/ui/table-duplicate-row-column-button/use-table-duplicate-row-column.ts +357 -0
  149. package/src/components/tiptap-node/table-node/ui/table-extend-row-column-button/index.tsx +2 -0
  150. package/src/components/tiptap-node/table-node/ui/table-extend-row-column-button/table-extend-row-column-button.css +17 -0
  151. package/src/components/tiptap-node/table-node/ui/table-extend-row-column-button/table-extend-row-column-button.tsx +240 -0
  152. package/src/components/tiptap-node/table-node/ui/table-extend-row-column-button/use-table-extend-row-column.ts +118 -0
  153. package/src/components/tiptap-node/table-node/ui/table-fit-to-width-button/index.tsx +2 -0
  154. package/src/components/tiptap-node/table-node/ui/table-fit-to-width-button/table-fit-to-width-button.tsx +98 -0
  155. package/src/components/tiptap-node/table-node/ui/table-fit-to-width-button/use-table-fit-to-width.ts +223 -0
  156. package/src/components/tiptap-node/table-node/ui/table-handle/index.tsx +2 -0
  157. package/src/components/tiptap-node/table-node/ui/table-handle/table-handle.tsx +163 -0
  158. package/src/components/tiptap-node/table-node/ui/table-handle/use-table-handle-positioning.ts +255 -0
  159. package/src/components/tiptap-node/table-node/ui/table-handle-menu/index.tsx +1 -0
  160. package/src/components/tiptap-node/table-node/ui/table-handle-menu/table-handle-menu.css +39 -0
  161. package/src/components/tiptap-node/table-node/ui/table-handle-menu/table-handle-menu.tsx +681 -0
  162. package/src/components/tiptap-node/table-node/ui/table-header-row-column-button/index.tsx +2 -0
  163. package/src/components/tiptap-node/table-node/ui/table-header-row-column-button/table-header-row-column-button.tsx +99 -0
  164. package/src/components/tiptap-node/table-node/ui/table-header-row-column-button/use-table-header-row-column.ts +227 -0
  165. package/src/components/tiptap-node/table-node/ui/table-merge-split-cell-button/index.tsx +2 -0
  166. package/src/components/tiptap-node/table-node/ui/table-merge-split-cell-button/table-merge-split-cell-button.tsx +125 -0
  167. package/src/components/tiptap-node/table-node/ui/table-merge-split-cell-button/use-table-merge-split-cell.ts +267 -0
  168. package/src/components/tiptap-node/table-node/ui/table-move-row-column-button/index.tsx +2 -0
  169. package/src/components/tiptap-node/table-node/ui/table-move-row-column-button/table-move-row-column-button.tsx +123 -0
  170. package/src/components/tiptap-node/table-node/ui/table-move-row-column-button/use-table-move-row-column.ts +431 -0
  171. package/src/components/tiptap-node/table-node/ui/table-selection-overlay/index.tsx +1 -0
  172. package/src/components/tiptap-node/table-node/ui/table-selection-overlay/table-selection-overlay.tsx +483 -0
  173. package/src/components/tiptap-node/table-node/ui/table-selection-overlay/use-resize-overlay.ts +78 -0
  174. package/src/components/tiptap-node/table-node/ui/table-sort-row-column-button/index.tsx +2 -0
  175. package/src/components/tiptap-node/table-node/ui/table-sort-row-column-button/table-sort-row-column-button.tsx +100 -0
  176. package/src/components/tiptap-node/table-node/ui/table-sort-row-column-button/use-table-sort-row-column.ts +444 -0
  177. package/src/components/tiptap-node/table-node/ui/table-trigger-button/index.tsx +3 -0
  178. package/src/components/tiptap-node/table-node/ui/table-trigger-button/table-grid-selector.css +39 -0
  179. package/src/components/tiptap-node/table-node/ui/table-trigger-button/table-grid-selector.tsx +219 -0
  180. package/src/components/tiptap-node/table-node/ui/table-trigger-button/table-trigger-button.tsx +132 -0
  181. package/src/components/tiptap-node/table-node/ui/table-trigger-button/use-table-trigger.ts +166 -0
  182. package/src/components/tiptap-ui/blockquote-button/blockquote-button.tsx +125 -0
  183. package/src/components/tiptap-ui/blockquote-button/index.tsx +2 -0
  184. package/src/components/tiptap-ui/blockquote-button/use-blockquote.ts +246 -0
  185. package/src/components/tiptap-ui/code-block-button/code-block-button.tsx +100 -0
  186. package/src/components/tiptap-ui/code-block-button/index.tsx +2 -0
  187. package/src/components/tiptap-ui/code-block-button/use-code-block.ts +256 -0
  188. package/src/components/tiptap-ui/color-highlight-button/color-highlight-button.css +32 -0
  189. package/src/components/tiptap-ui/color-highlight-button/color-highlight-button.tsx +171 -0
  190. package/src/components/tiptap-ui/color-highlight-button/index.tsx +2 -0
  191. package/src/components/tiptap-ui/color-highlight-button/use-color-highlight.ts +296 -0
  192. package/src/components/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +211 -0
  193. package/src/components/tiptap-ui/color-highlight-popover/index.tsx +1 -0
  194. package/src/components/tiptap-ui/color-menu/color-menu.tsx +178 -0
  195. package/src/components/tiptap-ui/color-menu/index.tsx +1 -0
  196. package/src/components/tiptap-ui/color-text-button/color-text-button.css +31 -0
  197. package/src/components/tiptap-ui/color-text-button/color-text-button.tsx +150 -0
  198. package/src/components/tiptap-ui/color-text-button/index.tsx +2 -0
  199. package/src/components/tiptap-ui/color-text-button/use-color-text.ts +251 -0
  200. package/src/components/tiptap-ui/color-text-popover/color-text-popover.css +25 -0
  201. package/src/components/tiptap-ui/color-text-popover/color-text-popover.tsx +360 -0
  202. package/src/components/tiptap-ui/color-text-popover/index.tsx +2 -0
  203. package/src/components/tiptap-ui/color-text-popover/use-color-text-popover.ts +229 -0
  204. package/src/components/tiptap-ui/copy-anchor-link-button/copy-anchor-link-button.tsx +118 -0
  205. package/src/components/tiptap-ui/copy-anchor-link-button/index.tsx +3 -0
  206. package/src/components/tiptap-ui/copy-anchor-link-button/use-copy-anchor-link.ts +252 -0
  207. package/src/components/tiptap-ui/copy-anchor-link-button/use-scroll-to-hash.ts +128 -0
  208. package/src/components/tiptap-ui/copy-to-clipboard-button/copy-to-clipboard-button.tsx +116 -0
  209. package/src/components/tiptap-ui/copy-to-clipboard-button/index.tsx +2 -0
  210. package/src/components/tiptap-ui/copy-to-clipboard-button/use-copy-to-clipboard.ts +234 -0
  211. package/src/components/tiptap-ui/delete-node-button/delete-node-button.tsx +98 -0
  212. package/src/components/tiptap-ui/delete-node-button/index.tsx +2 -0
  213. package/src/components/tiptap-ui/delete-node-button/use-delete-node.ts +236 -0
  214. package/src/components/tiptap-ui/drag-context-menu/drag-context-menu-types.ts +28 -0
  215. package/src/components/tiptap-ui/drag-context-menu/drag-context-menu.css +17 -0
  216. package/src/components/tiptap-ui/drag-context-menu/drag-context-menu.tsx +413 -0
  217. package/src/components/tiptap-ui/drag-context-menu/index.tsx +2 -0
  218. package/src/components/tiptap-ui/duplicate-button/duplicate-button.tsx +114 -0
  219. package/src/components/tiptap-ui/duplicate-button/index.tsx +2 -0
  220. package/src/components/tiptap-ui/duplicate-button/use-duplicate.ts +208 -0
  221. package/src/components/tiptap-ui/emoji-dropdown-menu/emoji-dropdown-menu.tsx +103 -0
  222. package/src/components/tiptap-ui/emoji-dropdown-menu/index.tsx +1 -0
  223. package/src/components/tiptap-ui/emoji-menu/emoji-menu-utils.ts +36 -0
  224. package/src/components/tiptap-ui/emoji-menu/emoji-menu.css +30 -0
  225. package/src/components/tiptap-ui/emoji-menu/emoji-menu.tsx +142 -0
  226. package/src/components/tiptap-ui/emoji-menu/index.tsx +2 -0
  227. package/src/components/tiptap-ui/emoji-trigger-button/emoji-trigger-button.tsx +128 -0
  228. package/src/components/tiptap-ui/emoji-trigger-button/index.tsx +2 -0
  229. package/src/components/tiptap-ui/emoji-trigger-button/use-emoji-trigger.ts +315 -0
  230. package/src/components/tiptap-ui/heading-button/heading-button.tsx +127 -0
  231. package/src/components/tiptap-ui/heading-button/index.tsx +2 -0
  232. package/src/components/tiptap-ui/heading-button/use-heading.ts +321 -0
  233. package/src/components/tiptap-ui/image-align-button/image-align-button.tsx +114 -0
  234. package/src/components/tiptap-ui/image-align-button/index.tsx +2 -0
  235. package/src/components/tiptap-ui/image-align-button/use-image-align.ts +295 -0
  236. package/src/components/tiptap-ui/image-caption-button/image-caption-button.tsx +77 -0
  237. package/src/components/tiptap-ui/image-caption-button/index.tsx +2 -0
  238. package/src/components/tiptap-ui/image-caption-button/use-image-caption.ts +212 -0
  239. package/src/components/tiptap-ui/image-download-button/image-download-button.tsx +104 -0
  240. package/src/components/tiptap-ui/image-download-button/index.tsx +2 -0
  241. package/src/components/tiptap-ui/image-download-button/use-image-download.ts +364 -0
  242. package/src/components/tiptap-ui/image-upload-button/image-upload-button.tsx +133 -0
  243. package/src/components/tiptap-ui/image-upload-button/index.tsx +2 -0
  244. package/src/components/tiptap-ui/image-upload-button/use-image-upload.ts +192 -0
  245. package/src/components/tiptap-ui/link-popover/index.tsx +2 -0
  246. package/src/components/tiptap-ui/link-popover/link-popover.tsx +271 -0
  247. package/src/components/tiptap-ui/link-popover/use-link-popover.ts +286 -0
  248. package/src/components/tiptap-ui/list-button/index.tsx +2 -0
  249. package/src/components/tiptap-ui/list-button/list-button.tsx +123 -0
  250. package/src/components/tiptap-ui/list-button/use-list.ts +326 -0
  251. package/src/components/tiptap-ui/mark-button/index.tsx +2 -0
  252. package/src/components/tiptap-ui/mark-button/mark-button.tsx +110 -0
  253. package/src/components/tiptap-ui/mark-button/use-mark.ts +195 -0
  254. package/src/components/tiptap-ui/mention-dropdown-menu/index.tsx +1 -0
  255. package/src/components/tiptap-ui/mention-dropdown-menu/mention-dropdown-menu.tsx +212 -0
  256. package/src/components/tiptap-ui/mention-trigger-button/index.tsx +2 -0
  257. package/src/components/tiptap-ui/mention-trigger-button/mention-trigger-button.tsx +122 -0
  258. package/src/components/tiptap-ui/mention-trigger-button/use-mention-trigger.ts +339 -0
  259. package/src/components/tiptap-ui/move-node-button/index.tsx +2 -0
  260. package/src/components/tiptap-ui/move-node-button/move-node-button.tsx +120 -0
  261. package/src/components/tiptap-ui/move-node-button/use-move-node.ts +207 -0
  262. package/src/components/tiptap-ui/reset-all-formatting-button/index.tsx +2 -0
  263. package/src/components/tiptap-ui/reset-all-formatting-button/reset-all-formatting-button.tsx +126 -0
  264. package/src/components/tiptap-ui/reset-all-formatting-button/use-reset-all-formatting.ts +250 -0
  265. package/src/components/tiptap-ui/slash-command-trigger-button/index.tsx +2 -0
  266. package/src/components/tiptap-ui/slash-command-trigger-button/slash-command-trigger-button.tsx +128 -0
  267. package/src/components/tiptap-ui/slash-command-trigger-button/use-slash-command-trigger.ts +255 -0
  268. package/src/components/tiptap-ui/slash-dropdown-menu/index.tsx +2 -0
  269. package/src/components/tiptap-ui/slash-dropdown-menu/slash-dropdown-menu.css +33 -0
  270. package/src/components/tiptap-ui/slash-dropdown-menu/slash-dropdown-menu.tsx +159 -0
  271. package/src/components/tiptap-ui/slash-dropdown-menu/use-slash-dropdown-menu.ts +317 -0
  272. package/src/components/tiptap-ui/text-align-button/index.tsx +2 -0
  273. package/src/components/tiptap-ui/text-align-button/text-align-button.tsx +120 -0
  274. package/src/components/tiptap-ui/text-align-button/use-text-align.ts +224 -0
  275. package/src/components/tiptap-ui/text-button/index.tsx +2 -0
  276. package/src/components/tiptap-ui/text-button/text-button.tsx +117 -0
  277. package/src/components/tiptap-ui/text-button/use-text.ts +264 -0
  278. package/src/components/tiptap-ui/turn-into-dropdown/index.tsx +2 -0
  279. package/src/components/tiptap-ui/turn-into-dropdown/turn-into-dropdown.tsx +192 -0
  280. package/src/components/tiptap-ui/turn-into-dropdown/use-turn-into-dropdown.ts +260 -0
  281. package/src/components/tiptap-ui/undo-redo-button/index.tsx +2 -0
  282. package/src/components/tiptap-ui/undo-redo-button/undo-redo-button.tsx +126 -0
  283. package/src/components/tiptap-ui/undo-redo-button/use-undo-redo.ts +184 -0
  284. package/src/components/tiptap-ui-primitive/avatar/avatar.css +83 -0
  285. package/src/components/tiptap-ui-primitive/avatar/avatar.tsx +239 -0
  286. package/src/components/tiptap-ui-primitive/avatar/index.tsx +1 -0
  287. package/src/components/tiptap-ui-primitive/badge/badge-colors.css +358 -0
  288. package/src/components/tiptap-ui-primitive/badge/badge-group.css +18 -0
  289. package/src/components/tiptap-ui-primitive/badge/badge.css +93 -0
  290. package/src/components/tiptap-ui-primitive/badge/badge.tsx +46 -0
  291. package/src/components/tiptap-ui-primitive/badge/index.tsx +1 -0
  292. package/src/components/tiptap-ui-primitive/button/button-colors.css +6 -0
  293. package/src/components/tiptap-ui-primitive/button/button-group.css +17 -0
  294. package/src/components/tiptap-ui-primitive/button/button.css +428 -0
  295. package/src/components/tiptap-ui-primitive/button/button.tsx +116 -0
  296. package/src/components/tiptap-ui-primitive/button/index.tsx +1 -0
  297. package/src/components/tiptap-ui-primitive/card/card.css +42 -0
  298. package/src/components/tiptap-ui-primitive/card/card.tsx +79 -0
  299. package/src/components/tiptap-ui-primitive/card/index.tsx +1 -0
  300. package/src/components/tiptap-ui-primitive/combobox/combobox.css +15 -0
  301. package/src/components/tiptap-ui-primitive/combobox/combobox.tsx +73 -0
  302. package/src/components/tiptap-ui-primitive/combobox/index.tsx +1 -0
  303. package/src/components/tiptap-ui-primitive/dropdown-menu/dropdown-menu.css +49 -0
  304. package/src/components/tiptap-ui-primitive/dropdown-menu/dropdown-menu.tsx +98 -0
  305. package/src/components/tiptap-ui-primitive/dropdown-menu/index.tsx +1 -0
  306. package/src/components/tiptap-ui-primitive/input/index.tsx +1 -0
  307. package/src/components/tiptap-ui-primitive/input/input.css +26 -0
  308. package/src/components/tiptap-ui-primitive/input/input.tsx +24 -0
  309. package/src/components/tiptap-ui-primitive/label/index.tsx +1 -0
  310. package/src/components/tiptap-ui-primitive/label/label.css +9 -0
  311. package/src/components/tiptap-ui-primitive/label/label.tsx +42 -0
  312. package/src/components/tiptap-ui-primitive/menu/index.tsx +5 -0
  313. package/src/components/tiptap-ui-primitive/menu/menu-context.ts +19 -0
  314. package/src/components/tiptap-ui-primitive/menu/menu-hooks.ts +102 -0
  315. package/src/components/tiptap-ui-primitive/menu/menu-types.ts +56 -0
  316. package/src/components/tiptap-ui-primitive/menu/menu-utils.ts +64 -0
  317. package/src/components/tiptap-ui-primitive/menu/menu.css +49 -0
  318. package/src/components/tiptap-ui-primitive/menu/menu.tsx +235 -0
  319. package/src/components/tiptap-ui-primitive/popover/index.tsx +1 -0
  320. package/src/components/tiptap-ui-primitive/popover/popover.css +49 -0
  321. package/src/components/tiptap-ui-primitive/popover/popover.tsx +37 -0
  322. package/src/components/tiptap-ui-primitive/separator/index.tsx +1 -0
  323. package/src/components/tiptap-ui-primitive/separator/separator.css +19 -0
  324. package/src/components/tiptap-ui-primitive/separator/separator.tsx +33 -0
  325. package/src/components/tiptap-ui-primitive/sidebar/index.tsx +1 -0
  326. package/src/components/tiptap-ui-primitive/sidebar/sidebar.css +140 -0
  327. package/src/components/tiptap-ui-primitive/sidebar/sidebar.tsx +299 -0
  328. package/src/components/tiptap-ui-primitive/spacer/index.tsx +1 -0
  329. package/src/components/tiptap-ui-primitive/spacer/spacer.tsx +26 -0
  330. package/src/components/tiptap-ui-primitive/textarea-autosize/index.tsx +1 -0
  331. package/src/components/tiptap-ui-primitive/textarea-autosize/textarea-autosize.tsx +18 -0
  332. package/src/components/tiptap-ui-primitive/toolbar/index.tsx +1 -0
  333. package/src/components/tiptap-ui-primitive/toolbar/toolbar.css +65 -0
  334. package/src/components/tiptap-ui-primitive/toolbar/toolbar.tsx +123 -0
  335. package/src/components/tiptap-ui-primitive/tooltip/index.tsx +1 -0
  336. package/src/components/tiptap-ui-primitive/tooltip/tooltip.css +21 -0
  337. package/src/components/tiptap-ui-primitive/tooltip/tooltip.tsx +237 -0
  338. package/src/components/tiptap-ui-utils/floating-element/floating-element-utils.ts +23 -0
  339. package/src/components/tiptap-ui-utils/floating-element/floating-element.tsx +343 -0
  340. package/src/components/tiptap-ui-utils/floating-element/index.tsx +2 -0
  341. package/src/components/tiptap-ui-utils/suggestion-menu/index.tsx +3 -0
  342. package/src/components/tiptap-ui-utils/suggestion-menu/suggestion-menu-types.ts +91 -0
  343. package/src/components/tiptap-ui-utils/suggestion-menu/suggestion-menu-utils.ts +87 -0
  344. package/src/components/tiptap-ui-utils/suggestion-menu/suggestion-menu.tsx +240 -0
  345. package/src/content/index.tsx +27 -0
  346. package/src/content/style.css +12 -0
  347. package/src/contexts/ai-context.tsx +65 -0
  348. package/src/contexts/app-context.tsx +159 -0
  349. package/src/contexts/user-context.tsx +138 -0
  350. package/src/editor/collaboration/index.tsx +64 -0
  351. package/src/editor/index.tsx +144 -42
  352. package/src/hooks/use-composed-ref.ts +47 -0
  353. package/src/hooks/use-cursor-visibility.ts +69 -0
  354. package/src/hooks/use-editor.ts +237 -0
  355. package/src/hooks/use-element-rect.ts +165 -0
  356. package/src/hooks/use-floating-element.ts +101 -0
  357. package/src/hooks/use-floating-toolbar-visibility.ts +123 -0
  358. package/src/hooks/use-is-breakpoint.ts +37 -0
  359. package/src/hooks/use-isomorphic-layout-effect.ts +11 -0
  360. package/src/hooks/use-menu-navigation.ts +182 -0
  361. package/src/hooks/use-on-click-outside.ts +135 -0
  362. package/src/hooks/use-scrolling.ts +75 -0
  363. package/src/hooks/use-throttled-callback.ts +48 -0
  364. package/src/hooks/use-tiptap-editor.ts +49 -0
  365. package/src/hooks/use-ui-editor-state.ts +29 -0
  366. package/src/hooks/use-unmount.ts +21 -0
  367. package/src/hooks/use-window-size.ts +88 -0
  368. package/src/index.ts +4 -7
  369. package/src/lib/tiptap-advanced-utils.ts +362 -0
  370. package/src/lib/tiptap-collab-utils.ts +289 -0
  371. package/src/lib/tiptap-utils.ts +612 -0
  372. package/src/locales/en.json +123 -0
  373. package/src/locales/zh-CN.json +123 -0
  374. package/src/locales/zh-TW.json +123 -0
  375. package/src/styles/variables.css +92 -0
  376. package/README.md +0 -458
  377. package/src/editor/constants.tsx +0 -66
  378. package/src/editor/container.css +0 -46
  379. package/src/editor/control/character-count/index.tsx +0 -39
  380. package/src/editor/control/drag-handle/index.tsx +0 -85
  381. package/src/editor/control/drag-handle/use.content.actions.ts +0 -71
  382. package/src/editor/control/drag-handle/use.data.ts +0 -29
  383. package/src/editor/control/drag-handle/use.handle.id.ts +0 -6
  384. package/src/editor/control/index.tsx +0 -35
  385. package/src/editor/editor.css +0 -626
  386. package/src/editor/extension/block-quote-figure/BlockquoteFigure.ts +0 -73
  387. package/src/editor/extension/block-quote-figure/Quote/Quote.ts +0 -31
  388. package/src/editor/extension/block-quote-figure/Quote/index.ts +0 -1
  389. package/src/editor/extension/block-quote-figure/QuoteCaption/QuoteCaption.ts +0 -54
  390. package/src/editor/extension/block-quote-figure/QuoteCaption/index.ts +0 -1
  391. package/src/editor/extension/block-quote-figure/index.ts +0 -1
  392. package/src/editor/extension/document/index.ts +0 -5
  393. package/src/editor/extension/figcaption/Figcaption.ts +0 -90
  394. package/src/editor/extension/figcaption/index.ts +0 -1
  395. package/src/editor/extension/figure/Figure.ts +0 -62
  396. package/src/editor/extension/figure/index.ts +0 -1
  397. package/src/editor/extension/font-size/FontSize.ts +0 -64
  398. package/src/editor/extension/font-size/index.ts +0 -1
  399. package/src/editor/extension/global-drag-handle/clipboard-serializer.ts +0 -28
  400. package/src/editor/extension/global-drag-handle/index.ts +0 -377
  401. package/src/editor/extension/heading/index.ts +0 -13
  402. package/src/editor/extension/horizontal-rule/HorizontalRule.ts +0 -10
  403. package/src/editor/extension/horizontal-rule/index.ts +0 -1
  404. package/src/editor/extension/image/index.ts +0 -5
  405. package/src/editor/extension/image-block/ImageBlock.ts +0 -103
  406. package/src/editor/extension/image-block/components/ImageBlockMenu.tsx +0 -100
  407. package/src/editor/extension/image-block/components/ImageBlockView.tsx +0 -47
  408. package/src/editor/extension/image-block/components/ImageBlockWidth.tsx +0 -40
  409. package/src/editor/extension/image-block/index.ts +0 -1
  410. package/src/editor/extension/image-upload/ImageUpload.ts +0 -58
  411. package/src/editor/extension/image-upload/index.ts +0 -1
  412. package/src/editor/extension/image-upload/view/ImageUpload.tsx +0 -27
  413. package/src/editor/extension/image-upload/view/ImageUploader.tsx +0 -64
  414. package/src/editor/extension/image-upload/view/hooks.ts +0 -109
  415. package/src/editor/extension/image-upload/view/index.tsx +0 -1
  416. package/src/editor/extension/index.ts +0 -30
  417. package/src/editor/extension/link/Link.ts +0 -39
  418. package/src/editor/extension/link/index.ts +0 -1
  419. package/src/editor/extension/multi-column/Column.ts +0 -33
  420. package/src/editor/extension/multi-column/Columns.ts +0 -65
  421. package/src/editor/extension/multi-column/index.ts +0 -2
  422. package/src/editor/extension/multi-column/menus/ColumnsMenu.tsx +0 -82
  423. package/src/editor/extension/multi-column/menus/index.ts +0 -1
  424. package/src/editor/extension/selection/Selection.ts +0 -36
  425. package/src/editor/extension/selection/index.ts +0 -1
  426. package/src/editor/extension/slash-command/MenuList.tsx +0 -145
  427. package/src/editor/extension/slash-command/groups.ts +0 -153
  428. package/src/editor/extension/slash-command/index.ts +0 -277
  429. package/src/editor/extension/slash-command/types.ts +0 -25
  430. package/src/editor/extension/table/Cell.ts +0 -126
  431. package/src/editor/extension/table/Header.ts +0 -89
  432. package/src/editor/extension/table/Row.ts +0 -8
  433. package/src/editor/extension/table/Table.ts +0 -9
  434. package/src/editor/extension/table/index.ts +0 -4
  435. package/src/editor/extension/table/menus/TableColumn/index.tsx +0 -73
  436. package/src/editor/extension/table/menus/TableColumn/utils.ts +0 -38
  437. package/src/editor/extension/table/menus/TableRow/index.tsx +0 -74
  438. package/src/editor/extension/table/menus/TableRow/utils.ts +0 -38
  439. package/src/editor/extension/table/menus/index.tsx +0 -2
  440. package/src/editor/extension/table/utils.ts +0 -258
  441. package/src/editor/extension/task-item/index.ts +0 -1
  442. package/src/editor/extension/task-item/task-item.ts +0 -225
  443. package/src/editor/extension/task-list/index.ts +0 -1
  444. package/src/editor/extension/task-list/task-list.ts +0 -81
  445. package/src/editor/extension/trailing-node/index.ts +0 -1
  446. package/src/editor/extension/trailing-node/trailing-node.ts +0 -70
  447. package/src/editor/extension/unique-id/index.ts +0 -1
  448. package/src/editor/extension/unique-id/uniqueId.ts +0 -123
  449. package/src/editor/hooks.ts +0 -264
  450. package/src/editor/menus/LinkMenu/LinkMenu.tsx +0 -75
  451. package/src/editor/menus/LinkMenu/index.tsx +0 -1
  452. package/src/editor/menus/TextMenu/TextMenu.tsx +0 -193
  453. package/src/editor/menus/TextMenu/components/AIDropdown.tsx +0 -140
  454. package/src/editor/menus/TextMenu/components/ContentTypePicker.tsx +0 -76
  455. package/src/editor/menus/TextMenu/components/EditLinkPopover.tsx +0 -25
  456. package/src/editor/menus/TextMenu/components/FontFamilyPicker.tsx +0 -84
  457. package/src/editor/menus/TextMenu/components/FontSizePicker.tsx +0 -56
  458. package/src/editor/menus/TextMenu/hooks/useTextmenuCommands.ts +0 -96
  459. package/src/editor/menus/TextMenu/hooks/useTextmenuContentTypes.ts +0 -86
  460. package/src/editor/menus/TextMenu/hooks/useTextmenuStates.ts +0 -50
  461. package/src/editor/menus/TextMenu/index.tsx +0 -2
  462. package/src/editor/menus/types.ts +0 -21
  463. package/src/editor/panels/Colorpicker/ColorButton.tsx +0 -35
  464. package/src/editor/panels/Colorpicker/Colorpicker.tsx +0 -67
  465. package/src/editor/panels/Colorpicker/index.tsx +0 -2
  466. package/src/editor/panels/LinkEditorPanel/LinkEditorPanel.tsx +0 -76
  467. package/src/editor/panels/LinkEditorPanel/index.tsx +0 -1
  468. package/src/editor/panels/LinkPreviewPanel/LinkPreviewPanel.tsx +0 -32
  469. package/src/editor/panels/LinkPreviewPanel/index.tsx +0 -1
  470. package/src/editor/panels/index.tsx +0 -3
  471. package/src/editor/types.tsx +0 -38
  472. package/src/editor/ui/Button/Button.tsx +0 -70
  473. package/src/editor/ui/Button/index.tsx +0 -2
  474. package/src/editor/ui/Dropdown/Dropdown.tsx +0 -39
  475. package/src/editor/ui/Dropdown/index.tsx +0 -1
  476. package/src/editor/ui/Icon.tsx +0 -21
  477. package/src/editor/ui/Loader/Loader.tsx +0 -39
  478. package/src/editor/ui/Loader/index.ts +0 -1
  479. package/src/editor/ui/Loader/types.ts +0 -7
  480. package/src/editor/ui/Panel/index.tsx +0 -109
  481. package/src/editor/ui/PopoverMenu.tsx +0 -127
  482. package/src/editor/ui/Spinner/Spinner.tsx +0 -10
  483. package/src/editor/ui/Spinner/index.tsx +0 -1
  484. package/src/editor/ui/Surface.tsx +0 -27
  485. package/src/editor/ui/Textarea/Textarea.tsx +0 -20
  486. package/src/editor/ui/Textarea/index.tsx +0 -1
  487. package/src/editor/ui/Toggle/Toggle.tsx +0 -39
  488. package/src/editor/ui/Toggle/index.tsx +0 -1
  489. package/src/editor/ui/Toolbar.tsx +0 -107
  490. package/src/editor/ui/Tooltip/index.tsx +0 -77
  491. package/src/editor/ui/Tooltip/types.ts +0 -17
  492. package/src/editor/utils/cssVar.ts +0 -14
  493. package/src/editor/utils/getRenderContainer.ts +0 -39
  494. package/src/editor/utils/index.ts +0 -16
  495. package/src/editor/utils/isCustomNodeSelected.ts +0 -47
  496. package/src/editor/utils/isTextSelected.ts +0 -25
  497. package/src/editor/utils/locale.ts +0 -5
  498. package/src/editor/viewer/index.tsx +0 -26
  499. package/src/globals.css +0 -1
  500. package/src/locales/en-us.ts +0 -133
  501. package/src/locales/zh-cn.ts +0 -133
  502. package/src/locales/zh-tw.ts +0 -133
@@ -0,0 +1,612 @@
1
+ import type { Node as PMNode } from "@tiptap/pm/model"
2
+ import type { Transaction } from "@tiptap/pm/state"
3
+ import {
4
+ AllSelection,
5
+ NodeSelection,
6
+ Selection,
7
+ TextSelection,
8
+ } from "@tiptap/pm/state"
9
+ import { cellAround, CellSelection } from "@tiptap/pm/tables"
10
+ import {
11
+ findParentNodeClosestToPos,
12
+ type Editor,
13
+ type NodeWithPos,
14
+ } from "@tiptap/react"
15
+
16
+ export const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
17
+
18
+ export const MAC_SYMBOLS: Record<string, string> = {
19
+ mod: "⌘",
20
+ command: "⌘",
21
+ meta: "⌘",
22
+ ctrl: "⌃",
23
+ control: "⌃",
24
+ alt: "⌥",
25
+ option: "⌥",
26
+ shift: "⇧",
27
+ backspace: "Del",
28
+ delete: "⌦",
29
+ enter: "⏎",
30
+ escape: "⎋",
31
+ capslock: "⇪",
32
+ } as const
33
+
34
+ export const SR_ONLY = {
35
+ position: "absolute",
36
+ width: "1px",
37
+ height: "1px",
38
+ padding: 0,
39
+ margin: "-1px",
40
+ overflow: "hidden",
41
+ clip: "rect(0, 0, 0, 0)",
42
+ whiteSpace: "nowrap",
43
+ borderWidth: 0,
44
+ } as const
45
+
46
+ export function cn(
47
+ ...classes: (string | boolean | undefined | null)[]
48
+ ): string {
49
+ return classes.filter(Boolean).join(" ")
50
+ }
51
+
52
+ /**
53
+ * Determines if the current platform is macOS
54
+ * @returns boolean indicating if the current platform is Mac
55
+ */
56
+ export function isMac(): boolean {
57
+ return (
58
+ typeof navigator !== "undefined" &&
59
+ navigator.platform.toLowerCase().includes("mac")
60
+ )
61
+ }
62
+
63
+ /**
64
+ * Formats a shortcut key based on the platform (Mac or non-Mac)
65
+ * @param key - The key to format (e.g., "ctrl", "alt", "shift")
66
+ * @param isMac - Boolean indicating if the platform is Mac
67
+ * @param capitalize - Whether to capitalize the key (default: true)
68
+ * @returns Formatted shortcut key symbol
69
+ */
70
+ export const formatShortcutKey = (
71
+ key: string,
72
+ isMac: boolean,
73
+ capitalize: boolean = true
74
+ ) => {
75
+ if (isMac) {
76
+ const lowerKey = key.toLowerCase()
77
+ return MAC_SYMBOLS[lowerKey] || (capitalize ? key.toUpperCase() : key)
78
+ }
79
+
80
+ return capitalize ? key.charAt(0).toUpperCase() + key.slice(1) : key
81
+ }
82
+
83
+ /**
84
+ * Parses a shortcut key string into an array of formatted key symbols
85
+ * @param shortcutKeys - The string of shortcut keys (e.g., "ctrl-alt-shift")
86
+ * @param delimiter - The delimiter used to split the keys (default: "-")
87
+ * @param capitalize - Whether to capitalize the keys (default: true)
88
+ * @returns Array of formatted shortcut key symbols
89
+ */
90
+ export const parseShortcutKeys = (props: {
91
+ shortcutKeys: string | undefined
92
+ delimiter?: string
93
+ capitalize?: boolean
94
+ }) => {
95
+ const { shortcutKeys, delimiter = "+", capitalize = true } = props
96
+
97
+ if (!shortcutKeys) return []
98
+
99
+ return shortcutKeys
100
+ .split(delimiter)
101
+ .map((key) => key.trim())
102
+ .map((key) => formatShortcutKey(key, isMac(), capitalize))
103
+ }
104
+
105
+ /**
106
+ * Checks if a mark exists in the editor schema
107
+ * @param markName - The name of the mark to check
108
+ * @param editor - The editor instance
109
+ * @returns boolean indicating if the mark exists in the schema
110
+ */
111
+ export const isMarkInSchema = (
112
+ markName: string,
113
+ editor: Editor | null
114
+ ): boolean => {
115
+ if (!editor?.schema) return false
116
+ return editor.schema.spec.marks.get(markName) !== undefined
117
+ }
118
+
119
+ /**
120
+ * Checks if a node exists in the editor schema
121
+ * @param nodeName - The name of the node to check
122
+ * @param editor - The editor instance
123
+ * @returns boolean indicating if the node exists in the schema
124
+ */
125
+ export const isNodeInSchema = (
126
+ nodeName: string,
127
+ editor: Editor | null
128
+ ): boolean => {
129
+ if (!editor?.schema) return false
130
+ return editor.schema.spec.nodes.get(nodeName) !== undefined
131
+ }
132
+
133
+ /**
134
+ * Moves the focus to the next node in the editor
135
+ * @param editor - The editor instance
136
+ * @returns boolean indicating if the focus was moved
137
+ */
138
+ export function focusNextNode(editor: Editor) {
139
+ const { state, view } = editor
140
+ const { doc, selection } = state
141
+
142
+ const nextSel = Selection.findFrom(selection.$to, 1, true)
143
+ if (nextSel) {
144
+ view.dispatch(state.tr.setSelection(nextSel).scrollIntoView())
145
+ return true
146
+ }
147
+
148
+ const paragraphType = state.schema.nodes.paragraph
149
+ if (!paragraphType) {
150
+ console.warn("No paragraph node type found in schema.")
151
+ return false
152
+ }
153
+
154
+ const end = doc.content.size
155
+ const para = paragraphType.create()
156
+ let tr = state.tr.insert(end, para)
157
+
158
+ // Place the selection inside the new paragraph
159
+ const $inside = tr.doc.resolve(end + 1)
160
+ tr = tr.setSelection(TextSelection.near($inside)).scrollIntoView()
161
+ view.dispatch(tr)
162
+ return true
163
+ }
164
+
165
+ /**
166
+ * Checks if a value is a valid number (not null, undefined, or NaN)
167
+ * @param value - The value to check
168
+ * @returns boolean indicating if the value is a valid number
169
+ */
170
+ export function isValidPosition(pos: number | null | undefined): pos is number {
171
+ return typeof pos === "number" && pos >= 0
172
+ }
173
+
174
+ /**
175
+ * Checks if one or more extensions are registered in the Tiptap editor.
176
+ * @param editor - The Tiptap editor instance
177
+ * @param extensionNames - A single extension name or an array of names to check
178
+ * @returns True if at least one of the extensions is available, false otherwise
179
+ */
180
+ export function isExtensionAvailable(
181
+ editor: Editor | null,
182
+ extensionNames: string | string[]
183
+ ): boolean {
184
+ if (!editor) return false
185
+
186
+ const names = Array.isArray(extensionNames)
187
+ ? extensionNames
188
+ : [extensionNames]
189
+
190
+ const found = names.some((name) =>
191
+ editor.extensionManager.extensions.some((ext) => ext.name === name)
192
+ )
193
+
194
+ if (!found) {
195
+ console.warn(
196
+ `None of the extensions [${names.join(", ")}] were found in the editor schema. Ensure they are included in the editor configuration.`
197
+ )
198
+ }
199
+
200
+ return found
201
+ }
202
+
203
+ /**
204
+ * Finds a node at the specified position with error handling
205
+ * @param editor The Tiptap editor instance
206
+ * @param position The position in the document to find the node
207
+ * @returns The node at the specified position, or null if not found
208
+ */
209
+ export function findNodeAtPosition(editor: Editor, position: number) {
210
+ try {
211
+ const node = editor.state.doc.nodeAt(position)
212
+ if (!node) {
213
+ console.warn(`No node found at position ${position}`)
214
+ return null
215
+ }
216
+ return node
217
+ } catch (error) {
218
+ console.error(`Error getting node at position ${position}:`, error)
219
+ return null
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Finds the position and instance of a node in the document
225
+ * @param props Object containing editor, node (optional), and nodePos (optional)
226
+ * @param props.editor The Tiptap editor instance
227
+ * @param props.node The node to find (optional if nodePos is provided)
228
+ * @param props.nodePos The position of the node to find (optional if node is provided)
229
+ * @returns An object with the position and node, or null if not found
230
+ */
231
+ export function findNodePosition(props: {
232
+ editor: Editor | null
233
+ node?: PMNode | null
234
+ nodePos?: number | null
235
+ }): { pos: number; node: PMNode } | null {
236
+ const { editor, node, nodePos } = props
237
+
238
+ if (!editor || !editor.state?.doc) return null
239
+
240
+ // Zero is valid position
241
+ const hasValidNode = node !== undefined && node !== null
242
+ const hasValidPos = isValidPosition(nodePos)
243
+
244
+ if (!hasValidNode && !hasValidPos) {
245
+ return null
246
+ }
247
+
248
+ // First search for the node in the document if we have a node
249
+ if (hasValidNode) {
250
+ let foundPos = -1
251
+ let foundNode: PMNode | null = null
252
+
253
+ editor.state.doc.descendants((currentNode, pos) => {
254
+ // TODO: Needed?
255
+ // if (currentNode.type && currentNode.type.name === node!.type.name) {
256
+ if (currentNode === node) {
257
+ foundPos = pos
258
+ foundNode = currentNode
259
+ return false
260
+ }
261
+ return true
262
+ })
263
+
264
+ if (foundPos !== -1 && foundNode !== null) {
265
+ return { pos: foundPos, node: foundNode }
266
+ }
267
+ }
268
+
269
+ // If we have a valid position, use findNodeAtPosition
270
+ if (hasValidPos) {
271
+ const nodeAtPos = findNodeAtPosition(editor, nodePos!)
272
+ if (nodeAtPos) {
273
+ return { pos: nodePos!, node: nodeAtPos }
274
+ }
275
+ }
276
+
277
+ return null
278
+ }
279
+
280
+ /**
281
+ * Determines whether the current selection contains a node whose type matches
282
+ * any of the provided node type names.
283
+ * @param editor Tiptap editor instance
284
+ * @param nodeTypeNames List of node type names to match against
285
+ * @param checkAncestorNodes Whether to check ancestor node types up the depth chain
286
+ */
287
+ export function isNodeTypeSelected(
288
+ editor: Editor | null,
289
+ nodeTypeNames: string[] = [],
290
+ checkAncestorNodes: boolean = false
291
+ ): boolean {
292
+ if (!editor || !editor.state.selection) return false
293
+
294
+ const { selection } = editor.state
295
+ if (selection.empty) return false
296
+
297
+ // Direct node selection check
298
+ if (selection instanceof NodeSelection) {
299
+ const selectedNode = selection.node
300
+ return selectedNode ? nodeTypeNames.includes(selectedNode.type.name) : false
301
+ }
302
+
303
+ // Depth-based ancestor node check
304
+ if (checkAncestorNodes) {
305
+ const { $from } = selection
306
+ for (let depth = $from.depth; depth > 0; depth--) {
307
+ const ancestorNode = $from.node(depth)
308
+ if (nodeTypeNames.includes(ancestorNode.type.name)) {
309
+ return true
310
+ }
311
+ }
312
+ }
313
+
314
+ return false
315
+ }
316
+
317
+ /**
318
+ * Check whether the current selection is fully within nodes
319
+ * whose type names are in the provided `types` list.
320
+ *
321
+ * - NodeSelection → checks the selected node.
322
+ * - Text/AllSelection → ensures all textblocks within [from, to) are allowed.
323
+ */
324
+ export function selectionWithinConvertibleTypes(
325
+ editor: Editor,
326
+ types: string[] = []
327
+ ): boolean {
328
+ if (!editor || types.length === 0) return false
329
+
330
+ const { state } = editor
331
+ const { selection } = state
332
+ const allowed = new Set(types)
333
+
334
+ if (selection instanceof NodeSelection) {
335
+ const nodeType = selection.node?.type?.name
336
+ return !!nodeType && allowed.has(nodeType)
337
+ }
338
+
339
+ if (selection instanceof TextSelection || selection instanceof AllSelection) {
340
+ let valid = true
341
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
342
+ if (node.isTextblock && !allowed.has(node.type.name)) {
343
+ valid = false
344
+ return false // stop early
345
+ }
346
+ return valid
347
+ })
348
+ return valid
349
+ }
350
+
351
+ return false
352
+ }
353
+
354
+ /**
355
+ * Handles image upload with progress tracking and abort capability
356
+ * @param file The file to upload
357
+ * @param onProgress Optional callback for tracking upload progress
358
+ * @param abortSignal Optional AbortSignal for cancelling the upload
359
+ * @returns Promise resolving to the URL of the uploaded image
360
+ */
361
+ export const handleImageUpload = async (
362
+ file: File,
363
+ onProgress?: (event: { progress: number }) => void,
364
+ abortSignal?: AbortSignal
365
+ ): Promise<string> => {
366
+ // Validate file
367
+ if (!file) {
368
+ throw new Error("No file provided")
369
+ }
370
+
371
+ if (file.size > MAX_FILE_SIZE) {
372
+ throw new Error(
373
+ `File size exceeds maximum allowed (${MAX_FILE_SIZE / (1024 * 1024)}MB)`
374
+ )
375
+ }
376
+
377
+ // For demo/testing: Simulate upload progress. In production, replace the following code
378
+ // with your own upload implementation.
379
+ for (let progress = 0; progress <= 100; progress += 10) {
380
+ if (abortSignal?.aborted) {
381
+ throw new Error("Upload cancelled")
382
+ }
383
+ await new Promise((resolve) => setTimeout(resolve, 500))
384
+ onProgress?.({ progress })
385
+ }
386
+
387
+ return "/images/tiptap-ui-placeholder-image.jpg"
388
+ }
389
+
390
+ type ProtocolOptions = {
391
+ /**
392
+ * The protocol scheme to be registered.
393
+ * @default '''
394
+ * @example 'ftp'
395
+ * @example 'git'
396
+ */
397
+ scheme: string
398
+
399
+ /**
400
+ * If enabled, it allows optional slashes after the protocol.
401
+ * @default false
402
+ * @example true
403
+ */
404
+ optionalSlashes?: boolean
405
+ }
406
+
407
+ type ProtocolConfig = Array<ProtocolOptions | string>
408
+
409
+ const ATTR_WHITESPACE =
410
+ // eslint-disable-next-line no-control-regex
411
+ /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g
412
+
413
+ export function isAllowedUri(
414
+ uri: string | undefined,
415
+ protocols?: ProtocolConfig
416
+ ) {
417
+ const allowedProtocols: string[] = [
418
+ "http",
419
+ "https",
420
+ "ftp",
421
+ "ftps",
422
+ "mailto",
423
+ "tel",
424
+ "callto",
425
+ "sms",
426
+ "cid",
427
+ "xmpp",
428
+ ]
429
+
430
+ if (protocols) {
431
+ protocols.forEach((protocol) => {
432
+ const nextProtocol =
433
+ typeof protocol === "string" ? protocol : protocol.scheme
434
+
435
+ if (nextProtocol) {
436
+ allowedProtocols.push(nextProtocol)
437
+ }
438
+ })
439
+ }
440
+
441
+ return (
442
+ !uri ||
443
+ uri.replace(ATTR_WHITESPACE, "").match(
444
+ new RegExp(
445
+ // eslint-disable-next-line no-useless-escape
446
+ `^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.\-]+(?:[^a-z+.\-:]|$))`,
447
+ "i"
448
+ )
449
+ )
450
+ )
451
+ }
452
+
453
+ export function sanitizeUrl(
454
+ inputUrl: string,
455
+ baseUrl: string,
456
+ protocols?: ProtocolConfig
457
+ ): string {
458
+ try {
459
+ const url = new URL(inputUrl, baseUrl)
460
+
461
+ if (isAllowedUri(url.href, protocols)) {
462
+ return url.href
463
+ }
464
+ } catch {
465
+ // If URL creation fails, it's considered invalid
466
+ }
467
+ return "#"
468
+ }
469
+
470
+ /**
471
+ * Update a single attribute on multiple nodes.
472
+ *
473
+ * @param tr - The transaction to mutate
474
+ * @param targets - Array of { node, pos }
475
+ * @param attrName - Attribute key to update
476
+ * @param next - New value OR updater function receiving previous value
477
+ * Pass `undefined` to remove the attribute.
478
+ * @returns true if at least one node was updated, false otherwise
479
+ */
480
+ export function updateNodesAttr<A extends string = string, V = unknown>(
481
+ tr: Transaction,
482
+ targets: readonly NodeWithPos[],
483
+ attrName: A,
484
+ next: V | ((prev: V | undefined) => V | undefined)
485
+ ): boolean {
486
+ if (!targets.length) return false
487
+
488
+ let changed = false
489
+
490
+ for (const { pos } of targets) {
491
+ // Always re-read from the transaction's current doc
492
+ const currentNode = tr.doc.nodeAt(pos)
493
+ if (!currentNode) continue
494
+
495
+ const prevValue = (currentNode.attrs as Record<string, unknown>)[
496
+ attrName
497
+ ] as V | undefined
498
+ const resolvedNext =
499
+ typeof next === "function"
500
+ ? (next as (p: V | undefined) => V | undefined)(prevValue)
501
+ : next
502
+
503
+ if (prevValue === resolvedNext) continue
504
+
505
+ const nextAttrs: Record<string, unknown> = { ...currentNode.attrs }
506
+ if (resolvedNext === undefined) {
507
+ // Remove the key entirely instead of setting null
508
+ delete nextAttrs[attrName]
509
+ } else {
510
+ nextAttrs[attrName] = resolvedNext
511
+ }
512
+
513
+ tr.setNodeMarkup(pos, undefined, nextAttrs)
514
+ changed = true
515
+ }
516
+
517
+ return changed
518
+ }
519
+
520
+ /**
521
+ * Selects the entire content of the current block node if the selection is empty.
522
+ * If the selection is not empty, it does nothing.
523
+ * @param editor The Tiptap editor instance
524
+ */
525
+ export function selectCurrentBlockContent(editor: Editor) {
526
+ const { selection, doc } = editor.state
527
+
528
+ if (!selection.empty) return
529
+
530
+ const $pos = selection.$from
531
+ let blockNode = null
532
+ let blockPos = -1
533
+
534
+ for (let depth = $pos.depth; depth >= 0; depth--) {
535
+ const node = $pos.node(depth)
536
+ const pos = $pos.start(depth)
537
+
538
+ if (node.isBlock && node.textContent.trim()) {
539
+ blockNode = node
540
+ blockPos = pos
541
+ break
542
+ }
543
+ }
544
+
545
+ if (blockNode && blockPos >= 0) {
546
+ const from = blockPos
547
+ const to = blockPos + blockNode.nodeSize - 2 // -2 to exclude the closing tag
548
+
549
+ if (from < to) {
550
+ const $from = doc.resolve(from)
551
+ const $to = doc.resolve(to)
552
+ const newSelection = TextSelection.between($from, $to, 1)
553
+
554
+ if (newSelection && !selection.eq(newSelection)) {
555
+ editor.view.dispatch(editor.state.tr.setSelection(newSelection))
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ /**
562
+ * Retrieves all nodes of specified types from the current selection.
563
+ * @param selection The current editor selection
564
+ * @param allowedNodeTypes An array of node type names to look for (e.g., ["image", "table"])
565
+ * @returns An array of objects containing the node and its position
566
+ */
567
+ export function getSelectedNodesOfType(
568
+ selection: Selection,
569
+ allowedNodeTypes: string[]
570
+ ): NodeWithPos[] {
571
+ const results: NodeWithPos[] = []
572
+ const allowed = new Set(allowedNodeTypes)
573
+
574
+ if (selection instanceof CellSelection) {
575
+ selection.forEachCell((node: PMNode, pos: number) => {
576
+ if (allowed.has(node.type.name)) {
577
+ results.push({ node, pos })
578
+ }
579
+ })
580
+ return results
581
+ }
582
+
583
+ if (selection instanceof NodeSelection) {
584
+ const { node, from: pos } = selection
585
+ if (node && allowed.has(node.type.name)) {
586
+ results.push({ node, pos })
587
+ }
588
+ return results
589
+ }
590
+
591
+ const { $anchor } = selection
592
+ const cell = cellAround($anchor)
593
+
594
+ if (cell) {
595
+ const cellNode = selection.$anchor.doc.nodeAt(cell.pos)
596
+ if (cellNode && allowed.has(cellNode.type.name)) {
597
+ results.push({ node: cellNode, pos: cell.pos })
598
+ return results
599
+ }
600
+ }
601
+
602
+ // Fallback: find parent nodes of allowed types
603
+ const parentNode = findParentNodeClosestToPos($anchor, (node) =>
604
+ allowed.has(node.type.name)
605
+ )
606
+
607
+ if (parentNode) {
608
+ results.push({ node: parentNode.node, pos: parentNode.pos })
609
+ }
610
+
611
+ return results
612
+ }