@meta-1/editor 0.0.29 → 1.0.1

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 +47 -66
  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,362 @@
1
+ import type { Attrs, Node } from "@tiptap/pm/model"
2
+ import { type Editor } from "@tiptap/react"
3
+ import { NodeSelection, TextSelection } from "@tiptap/pm/state"
4
+ import { findNodePosition, isValidPosition } from "./tiptap-utils"
5
+
6
+ /**
7
+ * Splits an array into chunks of specified size
8
+ */
9
+ export function chunkArray<T>(array: Array<T>, size: number): Array<Array<T>> {
10
+ return Array.from({ length: Math.ceil(array.length / size) }, (_, index) =>
11
+ array.slice(index * size, index * size + size)
12
+ )
13
+ }
14
+
15
+ /**
16
+ * Helper function to check if there's content above the current position
17
+ */
18
+ export function hasContentAbove(editor: Editor | null): {
19
+ hasContent: boolean
20
+ content: string
21
+ } {
22
+ if (!editor) return { hasContent: false, content: "" }
23
+
24
+ const { state } = editor
25
+ const { $from } = state.selection
26
+
27
+ for (let i = $from.index(0) - 1; i >= 0; i--) {
28
+ const node = state.doc.child(i)
29
+ const content = node.textContent.trim()
30
+
31
+ if (content) {
32
+ return { hasContent: true, content }
33
+ }
34
+ }
35
+
36
+ return { hasContent: false, content: "" }
37
+ }
38
+
39
+ /**
40
+ * Gets the active attributes of a specific mark in the current editor selection.
41
+ *
42
+ * @param editor - The Tiptap editor instance.
43
+ * @param markName - The name of the mark to look for (e.g., "highlight", "link").
44
+ * @returns The attributes of the active mark, or `null` if the mark is not active.
45
+ */
46
+ export function getActiveMarkAttrs(
47
+ editor: Editor | null,
48
+ markName: string
49
+ ): Attrs | null {
50
+ if (!editor) return null
51
+
52
+ const { state } = editor
53
+ const { from, to, empty, $from } = state.selection
54
+
55
+ if (empty) {
56
+ const mark = $from.marks().find((m) => m.type.name === markName)
57
+ return mark?.attrs ?? null
58
+ }
59
+
60
+ const seen = new Set<string>()
61
+ let foundAttrs: Attrs | null = null
62
+
63
+ state.doc.nodesBetween(from, to, (node) => {
64
+ if (!node.isText) return
65
+
66
+ for (const mark of node.marks) {
67
+ if (mark.type.name === markName && !seen.has(mark.type.name)) {
68
+ seen.add(mark.type.name)
69
+ foundAttrs = mark.attrs
70
+ }
71
+ }
72
+ })
73
+
74
+ return foundAttrs
75
+ }
76
+
77
+ /**
78
+ * Finds the position of a node in the editor selection
79
+ * @param params Object containing editor, node (optional), and nodePos (optional)
80
+ * @returns The position of the node in the selection or null if not found
81
+ */
82
+ export function findSelectionPosition(params: {
83
+ editor: Editor
84
+ node?: Node | null
85
+ nodePos?: number | null
86
+ }): number | null {
87
+ const { editor, node, nodePos } = params
88
+
89
+ if (isValidPosition(nodePos)) return nodePos
90
+
91
+ if (node) {
92
+ const found = findNodePosition({ editor, node })
93
+ if (found) return found.pos
94
+ }
95
+
96
+ const { selection } = editor.state
97
+ if (!selection.empty) return null
98
+
99
+ const resolvedPos = selection.$anchor
100
+ const nodeDepth = 1
101
+ const selectedNode = resolvedPos.node(nodeDepth)
102
+
103
+ return selectedNode ? resolvedPos.before(nodeDepth) : null
104
+ }
105
+
106
+ /**
107
+ * Gets the currently selected DOM element in the editor
108
+ * @param editor The Tiptap editor instance
109
+ * @returns The selected DOM element or null if no selection is present
110
+ */
111
+ export function getSelectedDOMElement(editor: Editor): HTMLElement | null {
112
+ const { state, view } = editor
113
+ const { selection } = state
114
+
115
+ if (selection instanceof NodeSelection) {
116
+ return view.nodeDOM(selection.from) as HTMLElement | null
117
+ }
118
+
119
+ if (selection instanceof TextSelection) {
120
+ const $anchor = selection.$anchor
121
+
122
+ // Ensure the depth is sufficient to avoid errors
123
+ if ($anchor.depth >= 1) {
124
+ const dom = view.nodeDOM($anchor.before(1))
125
+ if (dom instanceof HTMLElement) {
126
+ return dom
127
+ }
128
+ }
129
+ }
130
+
131
+ return null
132
+ }
133
+
134
+ /**
135
+ * Gets the closest node from the current selection in the editor based on criteria
136
+ * @param editor The Tiptap editor instance
137
+ * @param options Configuration options for finding the node
138
+ * @returns An object containing the closest matching node, its position, and depth, or null if not found
139
+ */
140
+ export function getClosestNode(
141
+ editor: Editor | null,
142
+ options?: {
143
+ nodeName?: string
144
+ isBlock?: boolean
145
+ predicate?: (node: Node) => boolean
146
+ }
147
+ ) {
148
+ if (!editor) return null
149
+
150
+ const { selection } = editor.state
151
+ const { $from } = selection
152
+ const { nodeName, isBlock = true, predicate } = options || {} // Default to block nodes
153
+
154
+ let depth = $from.depth
155
+ while (depth > 0) {
156
+ const node = $from.node(depth)
157
+
158
+ // Check all conditions
159
+ const matchesName = !nodeName || node.type.name === nodeName
160
+ const matchesBlock = node.type.isBlock === isBlock
161
+ const matchesPredicate = !predicate || predicate(node)
162
+
163
+ if (matchesName && matchesBlock && matchesPredicate) {
164
+ const pos = $from.before(depth)
165
+ return { node, pos, depth }
166
+ }
167
+ depth--
168
+ }
169
+ return null
170
+ }
171
+
172
+ /**
173
+ * Gets the closest node from a specific position in the document
174
+ * @param editor The Tiptap editor instance
175
+ * @param pos The position to search from
176
+ * @param options Configuration options for finding the node
177
+ * @returns An object containing the closest matching node, its position, and depth, or null if not found
178
+ */
179
+ export function getClosestNodeByPos(
180
+ editor: Editor | null,
181
+ pos: number,
182
+ options?: {
183
+ nodeName?: string
184
+ isBlock?: boolean
185
+ predicate?: (node: Node) => boolean
186
+ }
187
+ ) {
188
+ if (!editor) return null
189
+
190
+ const docSize = editor.state.doc.content.size
191
+ if (pos < 0 || pos > docSize) {
192
+ console.warn(`Position ${pos} is out of bounds (doc size: ${docSize})`)
193
+ return null
194
+ }
195
+
196
+ try {
197
+ const $pos = editor.state.doc.resolve(pos)
198
+ const { nodeName, isBlock = true, predicate } = options || {}
199
+
200
+ let depth = $pos.depth
201
+ while (depth > 0) {
202
+ const node = $pos.node(depth)
203
+
204
+ const matchesName = !nodeName || node.type.name === nodeName
205
+ const matchesBlock = node.type.isBlock === isBlock
206
+ const matchesPredicate = !predicate || predicate(node)
207
+
208
+ if (matchesName && matchesBlock && matchesPredicate) {
209
+ const nodePos = $pos.before(depth)
210
+ return { node, pos: nodePos, depth }
211
+ }
212
+ depth--
213
+ }
214
+ return null
215
+ } catch (error) {
216
+ console.error("Error resolving position:", error)
217
+ return null
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Convenience function to find closest block node (maintains backward compatibility)
223
+ */
224
+ export function getClosestBlockNode(editor: Editor | null) {
225
+ return getClosestNode(editor, { isBlock: true })
226
+ }
227
+
228
+ /**
229
+ * Convenience function to find closest node by name
230
+ */
231
+ export function getClosestNodeByName(editor: Editor | null, nodeName: string) {
232
+ return getClosestNode(editor, { nodeName })
233
+ }
234
+
235
+ /**
236
+ * Find multiple matching nodes up the tree
237
+ */
238
+ export function getAllMatchingNodes(
239
+ editor: Editor | null,
240
+ options?: {
241
+ nodeName?: string
242
+ isBlock?: boolean
243
+ predicate?: (node: Node) => boolean
244
+ }
245
+ ) {
246
+ if (!editor) return []
247
+
248
+ const { selection } = editor.state
249
+ const { nodeName, isBlock = true, predicate } = options || {}
250
+ const matches = []
251
+
252
+ const nodeMatches = (node: Node) => {
253
+ const matchesName = !nodeName || node.type.name === nodeName
254
+ const matchesBlock = node.type.isBlock === isBlock
255
+ const matchesPredicate = !predicate || predicate(node)
256
+ return matchesName && matchesBlock && matchesPredicate
257
+ }
258
+
259
+ if (selection instanceof NodeSelection) {
260
+ const selectedNode = selection.node
261
+ if (nodeMatches(selectedNode)) {
262
+ matches.push({
263
+ node: selectedNode,
264
+ pos: selection.from,
265
+ depth: 0,
266
+ })
267
+ }
268
+ }
269
+
270
+ const { $from } = selection
271
+ let depth = $from.depth
272
+
273
+ while (depth > 0) {
274
+ const node = $from.node(depth)
275
+
276
+ if (nodeMatches(node)) {
277
+ const pos = $from.before(depth)
278
+ matches.push({ node, pos, depth })
279
+ }
280
+ depth--
281
+ }
282
+
283
+ return matches
284
+ }
285
+
286
+ /**
287
+ * Gets the anchor node and its position in the editor.
288
+ * @param editor The Tiptap editor instance
289
+ * @param allowEmptySelection If true, still returns the node at the cursor position even if selection is empty
290
+ * @returns An object containing the anchor node and its position, or null if not found
291
+ */
292
+ export function getAnchorNodeAndPos(
293
+ editor: Editor | null,
294
+ allowEmptySelection: boolean = true
295
+ ): { node: Node; pos: number } | null {
296
+ if (!editor) return null
297
+
298
+ const { state } = editor
299
+ const { selection } = state
300
+
301
+ if (selection instanceof NodeSelection) {
302
+ const node = selection.node
303
+ const pos = selection.from
304
+
305
+ if (node && isValidPosition(pos)) {
306
+ return { node, pos }
307
+ }
308
+ }
309
+
310
+ if (selection.empty && !allowEmptySelection) return null
311
+
312
+ const $anchor = selection.$anchor
313
+ const depth = 1 // explicitly use depth 1
314
+ const node = $anchor.node(depth)
315
+ const pos = $anchor.before(depth)
316
+
317
+ return { node, pos }
318
+ }
319
+
320
+ /**
321
+ * Checks if the current selection in the editor contains any text.
322
+ *
323
+ * @param editor - The Tiptap editor instance.
324
+ * @returns `true` if the selection contains text, `false` otherwise.
325
+ */
326
+ export function selectionHasText(editor: Editor | null): boolean {
327
+ if (!editor) return false
328
+
329
+ const { state } = editor
330
+ const { selection, doc } = state
331
+
332
+ if (selection.empty) return false
333
+
334
+ const text = doc.textBetween(selection.from, selection.to, "\n", "\0")
335
+ return text.trim().length > 0
336
+ }
337
+
338
+ /**
339
+ * Retrieves a specific extension by name from the Tiptap editor.
340
+ * @param editor - The Tiptap editor instance
341
+ * @param extensionName - The name of the extension to retrieve
342
+ * @returns The extension instance if found, otherwise null
343
+ */
344
+ export function getEditorExtension(
345
+ editor: Editor | null,
346
+ extensionName: string
347
+ ) {
348
+ if (!editor) return null
349
+
350
+ const extension = editor.extensionManager.extensions.find(
351
+ (ext) => ext.name === extensionName
352
+ )
353
+
354
+ if (!extension) {
355
+ console.warn(
356
+ `Extension "${extensionName}" not found in the editor schema. Ensure it is included in the editor configuration.`
357
+ )
358
+ return null
359
+ }
360
+
361
+ return extension
362
+ }
@@ -0,0 +1,289 @@
1
+ import { NodeSelection, type Selection } from "@tiptap/pm/state"
2
+ import { CellSelection } from "@tiptap/pm/tables"
3
+ import type { JSONContent, Editor } from "@tiptap/react"
4
+ import { isTextSelection, isNodeSelection, posToDOMRect } from "@tiptap/react"
5
+
6
+ // TipTap Collaboration
7
+ export const TIPTAP_COLLAB_DOC_PREFIX =
8
+ process.env.NEXT_PUBLIC_TIPTAP_COLLAB_DOC_PREFIX || ""
9
+ export const TIPTAP_COLLAB_APP_ID =
10
+ process.env.NEXT_PUBLIC_TIPTAP_COLLAB_APP_ID || ""
11
+ export const TIPTAP_COLLAB_TOKEN =
12
+ process.env.NEXT_PUBLIC_TIPTAP_COLLAB_TOKEN || ""
13
+
14
+ // TipTap AI
15
+ export const TIPTAP_AI_APP_ID = process.env.NEXT_PUBLIC_TIPTAP_AI_APP_ID || ""
16
+ export const TIPTAP_AI_TOKEN = process.env.NEXT_PUBLIC_TIPTAP_AI_TOKEN || ""
17
+
18
+ export const USE_JWT_TOKEN_API_ENDPOINT =
19
+ process.env.NEXT_PUBLIC_USE_JWT_TOKEN_API_ENDPOINT || ""
20
+
21
+ const NODE_TYPE_LABELS: Record<string, string> = {
22
+ paragraph: "Text",
23
+ heading: "Heading",
24
+ blockquote: "Blockquote",
25
+ listItem: "List Item",
26
+ codeBlock: "Code Block",
27
+ table: "Table",
28
+ }
29
+ export type OverflowPosition = "none" | "top" | "bottom" | "both"
30
+
31
+ /**
32
+ * Utility function to get URL parameters
33
+ */
34
+ export const getUrlParam = (param: string): string | null => {
35
+ if (typeof window === "undefined") return null
36
+ const params = new URLSearchParams(window.location.search)
37
+ return params.get(param)
38
+ }
39
+
40
+ /**
41
+ * Returns a display name for the current node in the editor
42
+ * @param editor The Tiptap editor instance
43
+ * @returns The display name of the current node
44
+ */
45
+ export const getNodeDisplayName = (editor: Editor | null): string => {
46
+ if (!editor) return "Node"
47
+
48
+ const { selection } = editor.state
49
+
50
+ if (selection instanceof NodeSelection) {
51
+ const nodeType = selection.node.type.name
52
+ return NODE_TYPE_LABELS[nodeType] || nodeType.toLowerCase()
53
+ }
54
+
55
+ if (selection instanceof CellSelection) {
56
+ return "Table"
57
+ }
58
+
59
+ const { $anchor } = selection
60
+ const nodeType = $anchor.parent.type.name
61
+ return NODE_TYPE_LABELS[nodeType] || nodeType.toLowerCase()
62
+ }
63
+
64
+ /**
65
+ * Removes empty paragraph nodes from content
66
+ */
67
+ export const removeEmptyParagraphs = (content: JSONContent) => ({
68
+ ...content,
69
+ content: content.content?.filter(
70
+ (node) =>
71
+ node.type !== "paragraph" ||
72
+ node.content?.some((child) => child.text?.trim() || child.type !== "text")
73
+ ),
74
+ })
75
+
76
+ /**
77
+ * Determines how a target element overflows relative to a container element
78
+ */
79
+ export function getElementOverflowPosition(
80
+ targetElement: Element,
81
+ containerElement: HTMLElement
82
+ ): OverflowPosition {
83
+ const targetBounds = targetElement.getBoundingClientRect()
84
+ const containerBounds = containerElement.getBoundingClientRect()
85
+
86
+ const isOverflowingTop = targetBounds.top < containerBounds.top
87
+ const isOverflowingBottom = targetBounds.bottom > containerBounds.bottom
88
+
89
+ if (isOverflowingTop && isOverflowingBottom) return "both"
90
+ if (isOverflowingTop) return "top"
91
+ if (isOverflowingBottom) return "bottom"
92
+ return "none"
93
+ }
94
+
95
+ /**
96
+ * Checks if the current selection is valid for a given editor
97
+ */
98
+ export const isSelectionValid = (
99
+ editor: Editor | null,
100
+ selection?: Selection,
101
+ excludedNodeTypes: string[] = ["imageUpload", "horizontalRule"]
102
+ ): boolean => {
103
+ if (!editor) return false
104
+ if (!selection) selection = editor.state.selection
105
+
106
+ const { state } = editor
107
+ const { doc } = state
108
+ const { empty, from, to } = selection
109
+
110
+ const isEmptyTextBlock =
111
+ !doc.textBetween(from, to).length && isTextSelection(selection)
112
+ const isCodeBlock =
113
+ selection.$from.parent.type.spec.code ||
114
+ (isNodeSelection(selection) && selection.node.type.spec.code)
115
+ const isExcludedNode =
116
+ isNodeSelection(selection) &&
117
+ excludedNodeTypes.includes(selection.node.type.name)
118
+ const isTableCell = selection instanceof CellSelection
119
+
120
+ return (
121
+ !empty &&
122
+ !isEmptyTextBlock &&
123
+ !isCodeBlock &&
124
+ !isExcludedNode &&
125
+ !isTableCell
126
+ )
127
+ }
128
+
129
+ /**
130
+ * Checks if the current text selection is valid for editing
131
+ * - Not empty
132
+ * - Not a code block
133
+ * - Not a node selection
134
+ */
135
+ export const isTextSelectionValid = (editor: Editor | null): boolean => {
136
+ if (!editor) return false
137
+ const { state } = editor
138
+ const { selection } = state
139
+ const isValid =
140
+ isTextSelection(selection) &&
141
+ !selection.empty &&
142
+ !selection.$from.parent.type.spec.code &&
143
+ !isNodeSelection(selection)
144
+
145
+ return isValid
146
+ }
147
+
148
+ /**
149
+ * Gets the bounding rect of the current selection in the editor.
150
+ */
151
+ export const getSelectionBoundingRect = (editor: Editor): DOMRect | null => {
152
+ const { state } = editor.view
153
+ const { selection } = state
154
+ const { ranges } = selection
155
+
156
+ const from = Math.min(...ranges.map((range) => range.$from.pos))
157
+ const to = Math.max(...ranges.map((range) => range.$to.pos))
158
+
159
+ if (isNodeSelection(selection)) {
160
+ const node = editor.view.nodeDOM(from) as HTMLElement
161
+ if (node) {
162
+ return node.getBoundingClientRect()
163
+ }
164
+ }
165
+
166
+ return posToDOMRect(editor.view, from, to)
167
+ }
168
+
169
+ /**
170
+ * Generates a deterministic avatar URL from a user name
171
+ */
172
+ export const getAvatar = (name: string) => {
173
+ if (!name) {
174
+ return "/avatars/memoji_01.png"
175
+ }
176
+
177
+ let hash = 0
178
+ for (let i = 0; i < name.length; i++) {
179
+ hash = name.charCodeAt(i) + ((hash << 5) - hash)
180
+ hash = hash & hash
181
+ }
182
+
183
+ const randomFraction = (Math.abs(hash) % 1000000) / 1000000
184
+ const id = 1 + Math.floor(randomFraction * 20)
185
+ const idString = id.toString().padStart(2, "0")
186
+ return `/avatars/memoji_${idString}.png`
187
+ }
188
+
189
+ /**
190
+ * Fetch collaboration JWT token from the API
191
+ */
192
+ export const fetchCollabToken = async () => {
193
+ if (USE_JWT_TOKEN_API_ENDPOINT) {
194
+ try {
195
+ // Example API endpoint that returns a JWT token.
196
+ // TODO: implement this API endpoint in your app
197
+ const response = await fetch(`/api/collaboration`, {
198
+ method: "POST",
199
+ headers: {
200
+ "Content-Type": "application/json",
201
+ },
202
+ })
203
+
204
+ if (!response.ok) {
205
+ throw new Error(`Failed to fetch token: ${response.status}`)
206
+ }
207
+
208
+ const data = await response.json()
209
+ return data.token
210
+ } catch (error) {
211
+ console.error("Failed to fetch collaboration token:", error)
212
+ return null
213
+ }
214
+ }
215
+
216
+ // TODO: as a developer, use the example JWT token provided in the Tiptap
217
+ // Cloud dashboard for local development only. In production, implement an API
218
+ // endpoint that generates a new JWT token in the server. Then, call that API
219
+ // endpoint from this function.
220
+ // When you've implemented the API endpoint, remove the code below.
221
+ if (!TIPTAP_COLLAB_TOKEN) {
222
+ alert(`Set up your environment variables to connect to Tiptap Cloud:
223
+ - NEXT_PUBLIC_TIPTAP_COLLAB_DOC_PREFIX - Prefix for identifying collaborative documents
224
+ - NEXT_PUBLIC_TIPTAP_COLLAB_APP_ID - Your Document Server App ID
225
+ - NEXT_PUBLIC_TIPTAP_COLLAB_TOKEN - JWT token for accessing Collaboration services (do not use in production)
226
+ - NEXT_PUBLIC_TIPTAP_AI_APP_ID - Your AI App ID
227
+ - NEXT_PUBLIC_TIPTAP_AI_TOKEN - JWT token for accessing AI services (do not use in production)
228
+ Follow this guide: https://tiptap.dev/docs/ui-components/templates/notion-like-editor`)
229
+ } else {
230
+ console.warn(
231
+ "You are using the example JWT token provided in the Tiptap Cloud dashboard. This is only for local development and should not be used in production. In production, implement an API endpoint that generates a new JWT token in the server, and call that API endpoint from the fetchCollabToken function. More info in the docs: https://tiptap.dev/docs/ui-components/templates/notion-like-editor"
232
+ )
233
+ }
234
+
235
+ // A hardcoded token for demonstration purposes.
236
+ // TODO: remove this in production and use the API endpoint instead
237
+ return TIPTAP_COLLAB_TOKEN
238
+ }
239
+
240
+ /**
241
+ * Fetch AI JWT token from the API
242
+ */
243
+ export const fetchAiToken = async () => {
244
+ if (USE_JWT_TOKEN_API_ENDPOINT) {
245
+ try {
246
+ // Example API endpoint that returns a JWT token.
247
+ // TODO: implement this API endpoint in your app
248
+ const response = await fetch(`/api/ai`, {
249
+ method: "POST",
250
+ headers: {
251
+ "Content-Type": "application/json",
252
+ },
253
+ })
254
+
255
+ if (!response.ok) {
256
+ throw new Error(`Failed to fetch token: ${response.status}`)
257
+ }
258
+
259
+ const data = await response.json()
260
+ return data.token
261
+ } catch (error) {
262
+ console.error("Failed to fetch AI token:", error)
263
+ return null
264
+ }
265
+ }
266
+
267
+ // TODO: as a developer, use the example JWT token provided in the Tiptap
268
+ // Cloud dashboard for local development only. In production, implement an API
269
+ // endpoint that generates a new JWT token in the server. Then, call that API
270
+ // endpoint from this function.
271
+ // When you've implemented the API endpoint, remove the code below.
272
+ if (!TIPTAP_AI_TOKEN) {
273
+ alert(`Set up your environment variables to connect to Tiptap Cloud:
274
+ - NEXT_PUBLIC_TIPTAP_COLLAB_DOC_PREFIX - Prefix for identifying collaborative documents
275
+ - NEXT_PUBLIC_TIPTAP_COLLAB_APP_ID - Your Document Server App ID
276
+ - NEXT_PUBLIC_TIPTAP_COLLAB_TOKEN - JWT token for accessing Collaboration services (do not use in production)
277
+ - NEXT_PUBLIC_TIPTAP_AI_APP_ID - Your AI App ID
278
+ - NEXT_PUBLIC_TIPTAP_AI_TOKEN - JWT token for accessing AI services (do not use in production)
279
+ Follow this guide: https://tiptap.dev/docs/ui-components/templates/notion-like-editor`)
280
+ } else {
281
+ console.warn(
282
+ "You are using the example JWT token provided in the Tiptap Cloud dashboard. This is only for local development and should not be used in production. In production, implement an API endpoint that generates a new JWT token in the server, and call that API endpoint from the fetchAiToken function. More info in the docs: https://tiptap.dev/docs/ui-components/templates/notion-like-editor"
283
+ )
284
+ }
285
+
286
+ // A hardcoded token for demonstration purposes.
287
+ // TODO: remove this in production and use the API endpoint instead
288
+ return TIPTAP_AI_TOKEN
289
+ }