@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,444 @@
1
+ "use client";
2
+
3
+ import { useCallback, useMemo } from "react";
4
+ import type { Node } from "@tiptap/pm/model";
5
+ import type { Editor } from "@tiptap/react";
6
+ import { useTranslation } from "react-i18next";
7
+
8
+ // --- Hooks ---
9
+ import { useTiptapEditor } from "../../../../../hooks/use-tiptap-editor";
10
+ // --- Lib ---
11
+ import { isExtensionAvailable } from "../../../../../lib/tiptap-utils";
12
+ // --- Icons ---
13
+ import { ArrowDownAZIcon } from "../../../../tiptap-icons/arrow-down-a-z-icon";
14
+ import { ArrowDownZAIcon } from "../../../../tiptap-icons/arrow-down-z-a-icon";
15
+ import type { Orientation } from "../../lib/tiptap-table-utils";
16
+ import {
17
+ type CellInfo,
18
+ getRowOrColumnCells,
19
+ getTable,
20
+ getTableSelectionType,
21
+ isCellEmpty,
22
+ } from "../../lib/tiptap-table-utils";
23
+
24
+ export type SortDirection = "asc" | "desc";
25
+
26
+ export interface UseTableSortRowColumnConfig {
27
+ /**
28
+ * The Tiptap editor instance. If omitted, the hook will use
29
+ * the context/editor from `useTiptapEditor`.
30
+ */
31
+ editor?: Editor | null;
32
+ /**
33
+ * The index of the row or column to sort.
34
+ * If omitted, will use the current selection.
35
+ */
36
+ index?: number;
37
+ /**
38
+ * Whether you're sorting a row or a column.
39
+ * If omitted, will use the current selection.
40
+ */
41
+ orientation?: Orientation;
42
+ /**
43
+ * The position of the table in the document.
44
+ */
45
+ tablePos?: number;
46
+ /**
47
+ * The sort direction (ascending or descending).
48
+ */
49
+ direction: SortDirection;
50
+ /**
51
+ * Hide the button when sorting isn't currently possible.
52
+ * @default false
53
+ */
54
+ hideWhenUnavailable?: boolean;
55
+ /**
56
+ * Callback function called after a successful sort.
57
+ */
58
+ onSorted?: () => void;
59
+ }
60
+
61
+ const REQUIRED_EXTENSIONS = ["tableHandleExtension"];
62
+
63
+ export const tableSortRowColumnLabels: Record<Orientation, Record<SortDirection, string>> = {
64
+ row: {
65
+ asc: "Sort row A-Z",
66
+ desc: "Sort row Z-A",
67
+ },
68
+ column: {
69
+ asc: "Sort column A-Z",
70
+ desc: "Sort column Z-A",
71
+ },
72
+ };
73
+
74
+ export const tableSortRowColumnIcons = {
75
+ asc: ArrowDownAZIcon,
76
+ desc: ArrowDownZAIcon,
77
+ };
78
+
79
+ /**
80
+ * Check if a specific cell is a header cell
81
+ */
82
+ function isCellHeader(cellNode: Node | null): boolean {
83
+ if (!cellNode) return false;
84
+
85
+ return (
86
+ cellNode.type.name === "tableHeader" || cellNode.type.name === "table_header" || cellNode.attrs?.header === true
87
+ );
88
+ }
89
+
90
+ /**
91
+ * Extract text content from a cell node for sorting comparison
92
+ */
93
+ function getCellSortText(cellNode: Node | null): string {
94
+ if (!cellNode) return "";
95
+
96
+ let text = "";
97
+ cellNode.descendants((node) => {
98
+ if (node.isText) {
99
+ text += node.text || "";
100
+ }
101
+ return true;
102
+ });
103
+
104
+ return text.trim().toLowerCase();
105
+ }
106
+
107
+ /**
108
+ * Create a sortable item with all necessary data for restoration
109
+ */
110
+ interface SortableCell {
111
+ sortText: string;
112
+ originalNode: Node | null;
113
+ cellInfo: CellInfo;
114
+ originalIndex: number;
115
+ isHeader: boolean;
116
+ isEmpty: boolean;
117
+ }
118
+
119
+ /**
120
+ * Checks if a table row/column sort can be performed
121
+ * in the current editor state.
122
+ */
123
+ function canSortRowColumn({
124
+ editor,
125
+ index,
126
+ orientation,
127
+ tablePos,
128
+ }: {
129
+ editor: Editor | null;
130
+ index?: number;
131
+ orientation?: Orientation;
132
+ tablePos?: number;
133
+ }): boolean {
134
+ if (!editor || !editor.isEditable || !isExtensionAvailable(editor, REQUIRED_EXTENSIONS)) {
135
+ return false;
136
+ }
137
+
138
+ try {
139
+ const table = getTable(editor, tablePos);
140
+ if (!table) return false;
141
+
142
+ const cellData = getRowOrColumnCells(editor, index, orientation, tablePos);
143
+
144
+ if (cellData.orientation === "row") {
145
+ // Need at least 2 items to sort
146
+ if (table.map.width < 2) return false;
147
+ } else {
148
+ if (table.map.height < 2) return false;
149
+ }
150
+
151
+ if (cellData.mergedCells.length > 0) {
152
+ return false;
153
+ }
154
+
155
+ // Check if there's actual content to sort (excluding headers)
156
+ const hasContent = cellData.cells.some(
157
+ (cellInfo) => cellInfo.node && !isCellHeader(cellInfo.node) && !isCellEmpty(cellInfo.node),
158
+ );
159
+
160
+ if (!hasContent) {
161
+ return false;
162
+ }
163
+
164
+ return true;
165
+ } catch {
166
+ return false;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Executes the row/column sort in the editor while preserving marks and attributes.
172
+ * Header cells are excluded from sorting and remain in their original positions.
173
+ * Empty cells are always sorted to the end.
174
+ */
175
+ function tableSortRowColumn({
176
+ editor,
177
+ index,
178
+ orientation,
179
+ direction,
180
+ tablePos,
181
+ }: {
182
+ editor: Editor | null;
183
+ index?: number;
184
+ orientation?: Orientation;
185
+ direction: SortDirection;
186
+ tablePos?: number;
187
+ }): boolean {
188
+ if (!canSortRowColumn({ editor, index, orientation, tablePos }) || !editor) return false;
189
+
190
+ try {
191
+ const { state, view } = editor;
192
+ const tr = state.tr;
193
+
194
+ const cellData = getRowOrColumnCells(editor, index, orientation, tablePos);
195
+
196
+ if (cellData.mergedCells.length > 0) {
197
+ console.warn(`Cannot sort ${orientation} ${index}: contains merged cells`);
198
+ return false;
199
+ }
200
+
201
+ if (cellData.cells.length < 2) {
202
+ return false;
203
+ }
204
+
205
+ // Create sortable items, marking headers, data cells, and empty cells
206
+ const allItems: SortableCell[] = cellData.cells.map((cellInfo, originalIndex) => {
207
+ const isHeader = isCellHeader(cellInfo.node);
208
+ const isEmpty = cellInfo.node ? isCellEmpty(cellInfo.node) : true;
209
+ return {
210
+ sortText: getCellSortText(cellInfo.node),
211
+ originalNode: cellInfo.node,
212
+ cellInfo,
213
+ originalIndex,
214
+ isHeader,
215
+ isEmpty,
216
+ };
217
+ });
218
+
219
+ const dataItems = allItems.filter((item) => !item.isHeader);
220
+
221
+ if (dataItems.length < 2) {
222
+ console.log("No sortable data cells found (excluding headers)");
223
+ return false;
224
+ }
225
+
226
+ // Sort data items with special handling for empty cells
227
+ dataItems.sort((a, b) => {
228
+ if (a.isEmpty && !b.isEmpty) return 1;
229
+ if (!a.isEmpty && b.isEmpty) return -1;
230
+ if (a.isEmpty && b.isEmpty) return 0;
231
+
232
+ // For non-empty cells, sort normally
233
+ const comparison = a.sortText.localeCompare(b.sortText, undefined, {
234
+ sensitivity: "base",
235
+ });
236
+ return direction === "asc" ? comparison : -comparison;
237
+ });
238
+
239
+ const newCellNodes: Node[] = [];
240
+ let dataIndex = 0;
241
+
242
+ for (let i = 0; i < allItems.length; i++) {
243
+ const originalItem = allItems[i];
244
+ const targetCell = cellData.cells[i];
245
+
246
+ if (!targetCell || !originalItem) continue;
247
+
248
+ let nodeToPlace: Node | null = null;
249
+
250
+ if (originalItem.isHeader) {
251
+ // Keep header in its original position
252
+ nodeToPlace = originalItem.originalNode;
253
+ } else {
254
+ // Use the next sorted data cell
255
+ const sortedDataItem = dataItems[dataIndex];
256
+ nodeToPlace = sortedDataItem?.originalNode || null;
257
+ dataIndex++;
258
+ }
259
+
260
+ if (nodeToPlace && targetCell.node) {
261
+ const cellType = targetCell.node.type;
262
+ const newCellNode = cellType.create(nodeToPlace.attrs, nodeToPlace.content, nodeToPlace.marks);
263
+ newCellNodes.push(newCellNode);
264
+ } else {
265
+ newCellNodes.push(targetCell.node!);
266
+ }
267
+ }
268
+
269
+ // Replace each cell with the new cell (headers preserved, data sorted)
270
+ // We need to go in reverse order to maintain correct positions
271
+ const cellsToReplace = [...cellData.cells].reverse();
272
+ const newNodesToPlace = [...newCellNodes].reverse();
273
+
274
+ cellsToReplace.forEach((targetCell, reverseIndex) => {
275
+ const newNode = newNodesToPlace[reverseIndex];
276
+ if (newNode && targetCell.node) {
277
+ // Replace the entire cell node
278
+ const cellEnd = targetCell.pos + targetCell.node.nodeSize;
279
+ tr.replaceWith(targetCell.pos, cellEnd, newNode);
280
+ }
281
+ });
282
+
283
+ if (tr.docChanged) {
284
+ view.dispatch(tr);
285
+ return true;
286
+ }
287
+
288
+ return false;
289
+ } catch (error) {
290
+ console.error(`Error sorting table ${orientation}:`, error);
291
+ return false;
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Determines if the sort button should be shown
297
+ * based on editor state and config.
298
+ */
299
+ function shouldShowButton({
300
+ editor,
301
+ index,
302
+ orientation,
303
+ hideWhenUnavailable,
304
+ tablePos,
305
+ }: {
306
+ editor: Editor | null;
307
+ index?: number;
308
+ orientation?: Orientation;
309
+ hideWhenUnavailable: boolean;
310
+ tablePos: number | undefined;
311
+ }): boolean {
312
+ if (!editor || !editor.isEditable) return false;
313
+ if (!isExtensionAvailable(editor, REQUIRED_EXTENSIONS)) return false;
314
+
315
+ const table = getTable(editor, tablePos);
316
+ if (!table) return false;
317
+
318
+ const selectionType = getTableSelectionType(editor, index, orientation, tablePos);
319
+ if (!selectionType) return false;
320
+
321
+ return hideWhenUnavailable ? canSortRowColumn({ editor, index, orientation, tablePos }) : true;
322
+ }
323
+
324
+ /**
325
+ * Custom hook that provides **table row/column sorting**
326
+ * functionality for the Tiptap editor.
327
+ *
328
+ * **Header Handling:** Header cells are automatically detected and excluded
329
+ * from sorting. During a sort operation, header cells remain in their original
330
+ * positions while only data cells are rearranged. Headers are identified by
331
+ * node type (`tableHeader`) or attributes (`header: true`).
332
+ *
333
+ * **Empty Cell Handling:** Empty cells are always sorted to the end,
334
+ * regardless of sort direction (A-Z or Z-A).
335
+ *
336
+ * @example
337
+ * ```tsx
338
+ * // Sort currently selected row/column (smart mode)
339
+ * function SortButton() {
340
+ * const { isVisible, handleSort } = useTableSortRowColumn({ direction: "asc" })
341
+ *
342
+ * if (!isVisible) return null
343
+ *
344
+ * return <button onClick={handleSort}>Sort A-Z</button>
345
+ * }
346
+ *
347
+ * // Sort specific row, headers will be preserved
348
+ * function SortRowButton({ rowIndex }: { rowIndex: number }) {
349
+ * const { isVisible, handleSort, label, canSortRowColumn } = useTableSortRowColumn({
350
+ * index: rowIndex,
351
+ * orientation: "row",
352
+ * direction: "asc",
353
+ * hideWhenUnavailable: true,
354
+ * onSorted: () => console.log("Row sorted! Headers stayed in place."),
355
+ * })
356
+ *
357
+ * if (!isVisible) return null
358
+ *
359
+ * return (
360
+ * <button
361
+ * onClick={handleSort}
362
+ * disabled={!canSortRowColumn}
363
+ * aria-label={label}
364
+ * >
365
+ * {label}
366
+ * </button>
367
+ * )
368
+ * }
369
+ *
370
+ * // Sort with callback to handle the result
371
+ * function SmartSortButton() {
372
+ * const { isVisible, handleSort, label } = useTableSortRowColumn({
373
+ * direction: "desc",
374
+ * hideWhenUnavailable: true,
375
+ * onSorted: () => {
376
+ * console.log("Sort completed! Headers were automatically preserved.")
377
+ * }
378
+ * })
379
+ *
380
+ * if (!isVisible) return null
381
+ *
382
+ * return <button onClick={handleSort}>{label}</button>
383
+ * }
384
+ * ```
385
+ */
386
+ export function useTableSortRowColumn(config: UseTableSortRowColumnConfig = { direction: "asc" }) {
387
+ const {
388
+ editor: providedEditor,
389
+ index,
390
+ orientation,
391
+ tablePos,
392
+ direction,
393
+ hideWhenUnavailable = false,
394
+ onSorted,
395
+ } = config;
396
+
397
+ const { editor } = useTiptapEditor(providedEditor);
398
+ const { t } = useTranslation();
399
+ const selectionType = getTableSelectionType(editor, index, orientation);
400
+
401
+ const isVisible = shouldShowButton({
402
+ editor,
403
+ index,
404
+ orientation,
405
+ hideWhenUnavailable,
406
+ tablePos,
407
+ });
408
+
409
+ const canPerformSort = canSortRowColumn({
410
+ editor,
411
+ index,
412
+ orientation,
413
+ tablePos,
414
+ });
415
+
416
+ const handleSort = useCallback(() => {
417
+ const success = tableSortRowColumn({
418
+ editor,
419
+ index,
420
+ orientation,
421
+ direction,
422
+ tablePos,
423
+ });
424
+ if (success) onSorted?.();
425
+ return success;
426
+ }, [editor, index, orientation, direction, tablePos, onSorted]);
427
+
428
+ const label = useMemo(() => {
429
+ const orientationLabels = tableSortRowColumnLabels[selectionType?.orientation || "row"];
430
+ return orientationLabels[direction] || `Sort ${selectionType?.orientation} ${direction}`;
431
+ }, [selectionType, direction]);
432
+
433
+ const Icon = useMemo(() => {
434
+ return tableSortRowColumnIcons[direction] || ArrowDownAZIcon;
435
+ }, [direction]);
436
+
437
+ return {
438
+ isVisible,
439
+ canSortRowColumn: canPerformSort,
440
+ handleSort,
441
+ label: t(label),
442
+ Icon,
443
+ };
444
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./table-grid-selector"
2
+ export * from "./table-trigger-button"
3
+ export * from "./use-table-trigger"
@@ -0,0 +1,39 @@
1
+ @import "tailwindcss";
2
+
3
+ /* Grid container */
4
+ .tiptap-table-grid {
5
+ @apply grid gap-1 p-1;
6
+ grid-template-columns: repeat(var(--table-columns), 1rem);
7
+ }
8
+
9
+ /* Grid cell */
10
+ .tiptap-button[data-size="small"].tiptap-table-grid-cell {
11
+ @apply w-4 h-4 min-w-4 p-0 border border-gray-200 dark:border-gray-700 rounded-sm bg-gray-50 dark:bg-gray-800 cursor-pointer transition-all duration-150;
12
+ }
13
+
14
+ .tiptap-button[data-size="small"].tiptap-table-grid-cell.selected {
15
+ @apply bg-indigo-50 dark:bg-indigo-900 border-indigo-500;
16
+ }
17
+
18
+ /* Size indicator */
19
+ .tiptap-table-size-indicator {
20
+ @apply flex items-center justify-center gap-1 w-full mt-1;
21
+ }
22
+
23
+ .tiptap-table-size-indicator-item {
24
+ @apply flex flex-1 items-center justify-center gap-3 min-h-8 p-2 border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-black;
25
+ }
26
+
27
+ .tiptap-table-size-indicator-item .tiptap-table-column-icon,
28
+ .tiptap-table-size-indicator-item .tiptap-table-row-icon {
29
+ @apply w-4 h-4 text-gray-400 dark:text-gray-600;
30
+ }
31
+
32
+ .tiptap-table-size-indicator-text {
33
+ @apply text-sm font-normal text-center;
34
+ width: 1.781rem;
35
+ }
36
+
37
+ .tiptap-table-size-indicator-delimiter {
38
+ @apply flex-shrink-0 text-xs font-medium text-gray-500 dark:text-gray-600;
39
+ }
@@ -0,0 +1,219 @@
1
+ "use client"
2
+
3
+ import { forwardRef, useMemo, useCallback } from "react"
4
+
5
+ // --- UI Primitives ---
6
+ import { Button } from "../../../../tiptap-ui-primitive/button"
7
+
8
+ // --- Lib ---
9
+ import { cn } from "../../../../../lib/tiptap-utils"
10
+
11
+ // --- Icons ---
12
+ import { TableColumnIcon } from "../../../../tiptap-icons/table-column-icon"
13
+ import { TableRowIcon } from "../../../../tiptap-icons/table-row-icon"
14
+
15
+ import "./table-grid-selector.css"
16
+
17
+ // --- Types ---
18
+ export interface CellCoordinates {
19
+ row: number
20
+ col: number
21
+ }
22
+
23
+ export interface TableGridSelectorProps {
24
+ /**
25
+ * Initial number of rows to display in the grid
26
+ * @default 8
27
+ */
28
+ maxRows?: number
29
+ /**
30
+ * Initial number of columns to display in the grid
31
+ * @default 8
32
+ */
33
+ maxCols?: number
34
+ /**
35
+ * Currently hovered cell coordinates
36
+ */
37
+ hoveredCell: CellCoordinates | null
38
+ /**
39
+ * Callback when a cell is hovered
40
+ */
41
+ onCellHover: (row: number, col: number) => void
42
+ /**
43
+ * Callback when a cell is clicked
44
+ */
45
+ onCellClick: (row: number, col: number) => void
46
+ /**
47
+ * Callback when mouse leaves the grid
48
+ */
49
+ onMouseLeave?: () => void
50
+ /**
51
+ * Whether the grid cells should be disabled
52
+ * @default false
53
+ */
54
+ disabled?: boolean
55
+ /**
56
+ * Additional class name for the container
57
+ */
58
+ className?: string
59
+ /**
60
+ * Whether to show the size indicator
61
+ * @default true
62
+ */
63
+ showSizeIndicator?: boolean
64
+ }
65
+
66
+ interface GridCellProps {
67
+ row: number
68
+ col: number
69
+ isSelected: boolean
70
+ disabled: boolean
71
+ onMouseEnter: () => void
72
+ onClick: () => void
73
+ }
74
+
75
+ const isCellSelected = (
76
+ cell: CellCoordinates,
77
+ hoveredCell: CellCoordinates | null
78
+ ): boolean => {
79
+ if (!hoveredCell) return false
80
+ return cell.row <= hoveredCell.row && cell.col <= hoveredCell.col
81
+ }
82
+
83
+ const generateGridCells = (rows: number, cols: number): CellCoordinates[] => {
84
+ const totalCells = rows * cols
85
+ return Array.from({ length: totalCells }, (_, index) => ({
86
+ row: Math.floor(index / cols),
87
+ col: index % cols,
88
+ }))
89
+ }
90
+
91
+ const GridCell = ({
92
+ row,
93
+ col,
94
+ isSelected,
95
+ disabled,
96
+ onMouseEnter,
97
+ onClick,
98
+ }: GridCellProps) => (
99
+ <Button
100
+ data-size="small"
101
+ type="button"
102
+ className={cn("tiptap-table-grid-cell", isSelected && "selected")}
103
+ disabled={disabled}
104
+ onMouseEnter={onMouseEnter}
105
+ onClick={onClick}
106
+ aria-label={`Select ${row + 1}x${col + 1} table`}
107
+ />
108
+ )
109
+
110
+ const SizeIndicator = ({
111
+ hoveredCell,
112
+ }: {
113
+ hoveredCell: CellCoordinates | null
114
+ }) => {
115
+ const columns = hoveredCell ? hoveredCell.col + 1 : 1
116
+ const rows = hoveredCell ? hoveredCell.row + 1 : 1
117
+
118
+ return (
119
+ <div className="tiptap-table-size-indicator">
120
+ <div className="tiptap-table-size-indicator-item">
121
+ <TableColumnIcon className="tiptap-table-column-icon" />
122
+ <span className="tiptap-table-size-indicator-text">{columns}</span>
123
+ </div>
124
+ <span className="tiptap-table-size-indicator-delimiter">x</span>
125
+ <div className="tiptap-table-size-indicator-item">
126
+ <TableRowIcon className="tiptap-table-row-icon" />
127
+ <span className="tiptap-table-size-indicator-text">{rows}</span>
128
+ </div>
129
+ </div>
130
+ )
131
+ }
132
+
133
+ /**
134
+ * Reusable table grid selector component for selecting table dimensions.
135
+ *
136
+ * @example
137
+ * ```tsx
138
+ * const [hoveredCell, setHoveredCell] = useState<CellCoordinates | null>(null)
139
+ *
140
+ * <TableGridSelector
141
+ * maxRows={8}
142
+ * maxCols={8}
143
+ * hoveredCell={hoveredCell}
144
+ * onCellHover={(row, col) => setHoveredCell({ row, col })}
145
+ * onCellClick={(row, col) => insertTable(row + 1, col + 1)}
146
+ * onMouseLeave={() => setHoveredCell(null)}
147
+ * />
148
+ * ```
149
+ */
150
+ export const TableGridSelector = forwardRef<
151
+ HTMLDivElement,
152
+ TableGridSelectorProps
153
+ >(
154
+ (
155
+ {
156
+ maxRows = 8,
157
+ maxCols = 8,
158
+ hoveredCell,
159
+ onCellHover,
160
+ onCellClick,
161
+ onMouseLeave,
162
+ disabled = false,
163
+ className,
164
+ showSizeIndicator = true,
165
+ },
166
+ ref
167
+ ) => {
168
+ const gridCells = useMemo(
169
+ () => generateGridCells(maxRows, maxCols),
170
+ [maxRows, maxCols]
171
+ )
172
+
173
+ const gridStyle = useMemo(
174
+ () =>
175
+ ({
176
+ "--tt-table-columns": maxCols,
177
+ "--tt-table-rows": maxRows,
178
+ }) as React.CSSProperties,
179
+ [maxCols, maxRows]
180
+ )
181
+
182
+ const handleCellHover = useCallback(
183
+ (row: number, col: number) => () => onCellHover(row, col),
184
+ [onCellHover]
185
+ )
186
+
187
+ const handleCellClick = useCallback(
188
+ (row: number, col: number) => () => onCellClick(row, col),
189
+ [onCellClick]
190
+ )
191
+
192
+ return (
193
+ <>
194
+ <div
195
+ ref={ref}
196
+ className={cn("tiptap-table-grid", className)}
197
+ onMouseLeave={onMouseLeave}
198
+ style={gridStyle}
199
+ >
200
+ {gridCells.map((cell, index) => (
201
+ <GridCell
202
+ key={index}
203
+ row={cell.row}
204
+ col={cell.col}
205
+ isSelected={isCellSelected(cell, hoveredCell)}
206
+ disabled={disabled}
207
+ onMouseEnter={handleCellHover(cell.row, cell.col)}
208
+ onClick={handleCellClick(cell.row, cell.col)}
209
+ />
210
+ ))}
211
+ </div>
212
+
213
+ {showSizeIndicator && <SizeIndicator hoveredCell={hoveredCell} />}
214
+ </>
215
+ )
216
+ }
217
+ )
218
+
219
+ TableGridSelector.displayName = "TableGridSelector"