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