@multiplatform.one/rich-text 6.1.0 → 6.3.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/README.md +60 -0
- package/dist/cjs/RichEditor.cjs +84 -9
- package/dist/cjs/RichEditor.native.js +422 -35
- package/dist/cjs/RichEditor.native.js.map +1 -1
- package/dist/cjs/RichTextEditor/index.cjs +18 -2
- package/dist/cjs/RichTextEditor/index.native.js +18 -2
- package/dist/cjs/RichTextEditor/index.native.js.map +1 -1
- package/dist/cjs/constants.cjs +52 -29
- package/dist/cjs/constants.native.js +59 -29
- package/dist/cjs/constants.native.js.map +1 -1
- package/dist/cjs/editor/BlockDragHandle.cjs +22 -7
- package/dist/cjs/editor/BlockDragHandle.native.js +41 -7
- package/dist/cjs/editor/BlockDragHandle.native.js.map +1 -1
- package/dist/cjs/editor/SlashCommands.cjs +249 -293
- package/dist/cjs/editor/SlashCommands.native.js +306 -340
- package/dist/cjs/editor/SlashCommands.native.js.map +1 -1
- package/dist/cjs/editor/TentapEditor.native.js +44 -12
- package/dist/cjs/editor/TentapEditor.native.js.map +1 -1
- package/dist/cjs/editor/TiptapEditor.cjs +140 -33
- package/dist/cjs/editor/TiptapEditor.native.js +153 -33
- package/dist/cjs/editor/TiptapEditor.native.js.map +1 -1
- package/dist/cjs/editor/blockAnchor.cjs +43 -0
- package/dist/cjs/editor/blockAnchor.native.js +68 -0
- package/dist/cjs/editor/blockAnchor.native.js.map +1 -0
- package/dist/cjs/editor/codeBlockPreview.cjs +230 -0
- package/dist/cjs/editor/codeBlockPreview.native.js +265 -0
- package/dist/cjs/editor/codeBlockPreview.native.js.map +1 -0
- package/dist/cjs/editor/editorStyles.cjs +203 -34
- package/dist/cjs/editor/editorStyles.native.js +203 -34
- package/dist/cjs/editor/editorStyles.native.js.map +1 -1
- package/dist/cjs/editor/emoji.cjs +128 -0
- package/dist/cjs/editor/emoji.native.js +184 -0
- package/dist/cjs/editor/emoji.native.js.map +1 -0
- package/dist/cjs/editor/lazyKatex.cjs +78 -0
- package/dist/cjs/editor/lazyKatex.native.js +117 -0
- package/dist/cjs/editor/lazyKatex.native.js.map +1 -0
- package/dist/cjs/editor/markdown.cjs +216 -0
- package/dist/cjs/editor/markdown.native.js +278 -0
- package/dist/cjs/editor/markdown.native.js.map +1 -0
- package/dist/cjs/editor/mathematics.cjs +168 -0
- package/dist/cjs/editor/mathematics.native.js +202 -0
- package/dist/cjs/editor/mathematics.native.js.map +1 -0
- package/dist/cjs/editor/media.cjs +138 -0
- package/dist/cjs/editor/media.native.js +172 -0
- package/dist/cjs/editor/media.native.js.map +1 -0
- package/dist/cjs/editor/mentions.cjs +73 -0
- package/dist/cjs/editor/mentions.native.js +84 -0
- package/dist/cjs/editor/mentions.native.js.map +1 -0
- package/dist/cjs/editor/pasteCleanup.cjs +83 -0
- package/dist/cjs/editor/pasteCleanup.native.js +175 -0
- package/dist/cjs/editor/pasteCleanup.native.js.map +1 -0
- package/dist/cjs/editor/suggestionPopup.cjs +297 -0
- package/dist/cjs/editor/suggestionPopup.native.js +327 -0
- package/dist/cjs/editor/suggestionPopup.native.js.map +1 -0
- package/dist/cjs/preview.cjs +263 -0
- package/dist/cjs/preview.native.js +294 -0
- package/dist/cjs/preview.native.js.map +1 -0
- package/dist/cjs/shared/t.cjs +53 -0
- package/dist/cjs/shared/t.native.js +56 -0
- package/dist/cjs/shared/t.native.js.map +1 -0
- package/dist/cjs/shared/url.cjs +35 -0
- package/dist/cjs/shared/url.native.js +38 -0
- package/dist/cjs/shared/url.native.js.map +1 -0
- package/dist/cjs/styled.cjs +13 -6
- package/dist/cjs/styled.native.js +13 -6
- package/dist/cjs/styled.native.js.map +1 -1
- package/dist/cjs/toolbar/BubbleToolbar.cjs +10 -8
- package/dist/cjs/toolbar/BubbleToolbar.native.js +10 -8
- package/dist/cjs/toolbar/BubbleToolbar.native.js.map +1 -1
- package/dist/cjs/toolbar/CodeBlockBubble.cjs +59 -23
- package/dist/cjs/toolbar/CodeBlockBubble.native.js +71 -25
- package/dist/cjs/toolbar/CodeBlockBubble.native.js.map +1 -1
- package/dist/cjs/toolbar/ColorPicker.cjs +19 -54
- package/dist/cjs/toolbar/ColorPicker.native.js +81 -179
- package/dist/cjs/toolbar/ColorPicker.native.js.map +1 -1
- package/dist/cjs/toolbar/FixedToolbar.cjs +33 -10
- package/dist/cjs/toolbar/FixedToolbar.native.js +46 -54
- package/dist/cjs/toolbar/FixedToolbar.native.js.map +1 -1
- package/dist/cjs/toolbar/HeadingPicker.cjs +32 -39
- package/dist/cjs/toolbar/HeadingPicker.native.js +61 -51
- package/dist/cjs/toolbar/HeadingPicker.native.js.map +1 -1
- package/dist/cjs/toolbar/ImageBubble.cjs +20 -43
- package/dist/cjs/toolbar/ImageBubble.native.js +20 -43
- package/dist/cjs/toolbar/ImageBubble.native.js.map +1 -1
- package/dist/cjs/toolbar/ImageDialog.cjs +5 -4
- package/dist/cjs/toolbar/ImageDialog.native.js +76 -65
- package/dist/cjs/toolbar/ImageDialog.native.js.map +1 -1
- package/dist/cjs/toolbar/LinkBubble.cjs +23 -70
- package/dist/cjs/toolbar/LinkBubble.native.js +23 -70
- package/dist/cjs/toolbar/LinkBubble.native.js.map +1 -1
- package/dist/cjs/toolbar/LinkDialog.cjs +19 -18
- package/dist/cjs/toolbar/LinkDialog.native.js +86 -83
- package/dist/cjs/toolbar/LinkDialog.native.js.map +1 -1
- package/dist/cjs/toolbar/ListPicker.cjs +32 -43
- package/dist/cjs/toolbar/ListPicker.native.js +43 -44
- package/dist/cjs/toolbar/ListPicker.native.js.map +1 -1
- package/dist/cjs/toolbar/MathBubble.cjs +159 -0
- package/dist/cjs/toolbar/MathBubble.native.js +169 -0
- package/dist/cjs/toolbar/MathBubble.native.js.map +1 -0
- package/dist/cjs/toolbar/MoreDropdown.cjs +51 -98
- package/dist/cjs/toolbar/MoreDropdown.native.js +73 -98
- package/dist/cjs/toolbar/MoreDropdown.native.js.map +1 -1
- package/dist/cjs/toolbar/StatusBar.cjs +19 -10
- package/dist/cjs/toolbar/StatusBar.native.js +19 -10
- package/dist/cjs/toolbar/StatusBar.native.js.map +1 -1
- package/dist/cjs/toolbar/TableBubble.cjs +77 -95
- package/dist/cjs/toolbar/TableBubble.native.js +73 -71
- package/dist/cjs/toolbar/TableBubble.native.js.map +1 -1
- package/dist/cjs/toolbar/ToolbarButton.cjs +86 -21
- package/dist/cjs/toolbar/ToolbarButton.native.js +14 -4
- package/dist/cjs/toolbar/ToolbarButton.native.js.map +1 -1
- package/dist/cjs/toolbar/icons.cjs +111 -468
- package/dist/cjs/toolbar/shortcuts.cjs +73 -24
- package/dist/cjs/toolbar/shortcuts.native.js +73 -24
- package/dist/cjs/toolbar/shortcuts.native.js.map +1 -1
- package/dist/cjs/toolbar/useHorizontalScroll.cjs +25 -5
- package/dist/cjs/toolbar/useHorizontalScroll.native.js +25 -5
- package/dist/cjs/toolbar/useHorizontalScroll.native.js.map +1 -1
- package/dist/cjs/toolbar/useRovingFocus.cjs +80 -0
- package/dist/cjs/toolbar/useRovingFocus.native.js +113 -0
- package/dist/cjs/toolbar/useRovingFocus.native.js.map +1 -0
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/esm/RichEditor.mjs +85 -10
- package/dist/esm/RichEditor.mjs.map +1 -1
- package/dist/esm/RichEditor.native.js +425 -38
- package/dist/esm/RichEditor.native.js.map +1 -1
- package/dist/esm/RichTextEditor/index.mjs +18 -2
- package/dist/esm/RichTextEditor/index.mjs.map +1 -1
- package/dist/esm/RichTextEditor/index.native.js +18 -2
- package/dist/esm/RichTextEditor/index.native.js.map +1 -1
- package/dist/esm/constants.mjs +47 -29
- package/dist/esm/constants.mjs.map +1 -1
- package/dist/esm/constants.native.js +54 -29
- package/dist/esm/constants.native.js.map +1 -1
- package/dist/esm/editor/BlockDragHandle.mjs +22 -7
- package/dist/esm/editor/BlockDragHandle.mjs.map +1 -1
- package/dist/esm/editor/BlockDragHandle.native.js +41 -7
- package/dist/esm/editor/BlockDragHandle.native.js.map +1 -1
- package/dist/esm/editor/SlashCommands.mjs +250 -294
- package/dist/esm/editor/SlashCommands.mjs.map +1 -1
- package/dist/esm/editor/SlashCommands.native.js +307 -341
- package/dist/esm/editor/SlashCommands.native.js.map +1 -1
- package/dist/esm/editor/TentapEditor.native.js +45 -13
- package/dist/esm/editor/TentapEditor.native.js.map +1 -1
- package/dist/esm/editor/TiptapEditor.mjs +142 -35
- package/dist/esm/editor/TiptapEditor.mjs.map +1 -1
- package/dist/esm/editor/TiptapEditor.native.js +155 -35
- package/dist/esm/editor/TiptapEditor.native.js.map +1 -1
- package/dist/esm/editor/blockAnchor.mjs +18 -0
- package/dist/esm/editor/blockAnchor.mjs.map +1 -0
- package/dist/esm/editor/blockAnchor.native.js +40 -0
- package/dist/esm/editor/blockAnchor.native.js.map +1 -0
- package/dist/esm/editor/codeBlockPreview.mjs +190 -0
- package/dist/esm/editor/codeBlockPreview.mjs.map +1 -0
- package/dist/esm/editor/codeBlockPreview.native.js +222 -0
- package/dist/esm/editor/codeBlockPreview.native.js.map +1 -0
- package/dist/esm/editor/editorStyles.mjs +203 -34
- package/dist/esm/editor/editorStyles.mjs.map +1 -1
- package/dist/esm/editor/editorStyles.native.js +203 -34
- package/dist/esm/editor/editorStyles.native.js.map +1 -1
- package/dist/esm/editor/emoji.mjs +88 -0
- package/dist/esm/editor/emoji.mjs.map +1 -0
- package/dist/esm/editor/emoji.native.js +141 -0
- package/dist/esm/editor/emoji.native.js.map +1 -0
- package/dist/esm/editor/lazyKatex.mjs +40 -0
- package/dist/esm/editor/lazyKatex.mjs.map +1 -0
- package/dist/esm/editor/lazyKatex.native.js +76 -0
- package/dist/esm/editor/lazyKatex.native.js.map +1 -0
- package/dist/esm/editor/markdown.mjs +179 -0
- package/dist/esm/editor/markdown.mjs.map +1 -0
- package/dist/esm/editor/markdown.native.js +238 -0
- package/dist/esm/editor/markdown.native.js.map +1 -0
- package/dist/esm/editor/mathematics.mjs +142 -0
- package/dist/esm/editor/mathematics.mjs.map +1 -0
- package/dist/esm/editor/mathematics.native.js +173 -0
- package/dist/esm/editor/mathematics.native.js.map +1 -0
- package/dist/esm/editor/media.mjs +113 -0
- package/dist/esm/editor/media.mjs.map +1 -0
- package/dist/esm/editor/media.native.js +144 -0
- package/dist/esm/editor/media.native.js.map +1 -0
- package/dist/esm/editor/mentions.mjs +37 -0
- package/dist/esm/editor/mentions.mjs.map +1 -0
- package/dist/esm/editor/mentions.native.js +45 -0
- package/dist/esm/editor/mentions.native.js.map +1 -0
- package/dist/esm/editor/pasteCleanup.mjs +57 -0
- package/dist/esm/editor/pasteCleanup.mjs.map +1 -0
- package/dist/esm/editor/pasteCleanup.native.js +146 -0
- package/dist/esm/editor/pasteCleanup.native.js.map +1 -0
- package/dist/esm/editor/suggestionPopup.mjs +268 -0
- package/dist/esm/editor/suggestionPopup.mjs.map +1 -0
- package/dist/esm/editor/suggestionPopup.native.js +295 -0
- package/dist/esm/editor/suggestionPopup.native.js.map +1 -0
- package/dist/esm/preview.mjs +236 -0
- package/dist/esm/preview.mjs.map +1 -0
- package/dist/esm/preview.native.js +264 -0
- package/dist/esm/preview.native.js.map +1 -0
- package/dist/esm/shared/t.mjs +17 -0
- package/dist/esm/shared/t.mjs.map +1 -0
- package/dist/esm/shared/t.native.js +17 -0
- package/dist/esm/shared/t.native.js.map +1 -0
- package/dist/esm/shared/url.mjs +10 -0
- package/dist/esm/shared/url.mjs.map +1 -0
- package/dist/esm/shared/url.native.js +10 -0
- package/dist/esm/shared/url.native.js.map +1 -0
- package/dist/esm/styled.mjs +13 -6
- package/dist/esm/styled.mjs.map +1 -1
- package/dist/esm/styled.native.js +13 -6
- package/dist/esm/styled.native.js.map +1 -1
- package/dist/esm/toolbar/BubbleToolbar.mjs +11 -9
- package/dist/esm/toolbar/BubbleToolbar.mjs.map +1 -1
- package/dist/esm/toolbar/BubbleToolbar.native.js +11 -9
- package/dist/esm/toolbar/BubbleToolbar.native.js.map +1 -1
- package/dist/esm/toolbar/CodeBlockBubble.mjs +60 -24
- package/dist/esm/toolbar/CodeBlockBubble.mjs.map +1 -1
- package/dist/esm/toolbar/CodeBlockBubble.native.js +72 -26
- package/dist/esm/toolbar/CodeBlockBubble.native.js.map +1 -1
- package/dist/esm/toolbar/ColorPicker.mjs +21 -56
- package/dist/esm/toolbar/ColorPicker.mjs.map +1 -1
- package/dist/esm/toolbar/ColorPicker.native.js +82 -180
- package/dist/esm/toolbar/ColorPicker.native.js.map +1 -1
- package/dist/esm/toolbar/FixedToolbar.mjs +34 -11
- package/dist/esm/toolbar/FixedToolbar.mjs.map +1 -1
- package/dist/esm/toolbar/FixedToolbar.native.js +47 -55
- package/dist/esm/toolbar/FixedToolbar.native.js.map +1 -1
- package/dist/esm/toolbar/HeadingPicker.mjs +34 -41
- package/dist/esm/toolbar/HeadingPicker.mjs.map +1 -1
- package/dist/esm/toolbar/HeadingPicker.native.js +63 -53
- package/dist/esm/toolbar/HeadingPicker.native.js.map +1 -1
- package/dist/esm/toolbar/ImageBubble.mjs +20 -43
- package/dist/esm/toolbar/ImageBubble.mjs.map +1 -1
- package/dist/esm/toolbar/ImageBubble.native.js +20 -43
- package/dist/esm/toolbar/ImageBubble.native.js.map +1 -1
- package/dist/esm/toolbar/ImageDialog.mjs +5 -4
- package/dist/esm/toolbar/ImageDialog.mjs.map +1 -1
- package/dist/esm/toolbar/ImageDialog.native.js +75 -64
- package/dist/esm/toolbar/ImageDialog.native.js.map +1 -1
- package/dist/esm/toolbar/LinkBubble.mjs +23 -70
- package/dist/esm/toolbar/LinkBubble.mjs.map +1 -1
- package/dist/esm/toolbar/LinkBubble.native.js +23 -70
- package/dist/esm/toolbar/LinkBubble.native.js.map +1 -1
- package/dist/esm/toolbar/LinkDialog.mjs +17 -16
- package/dist/esm/toolbar/LinkDialog.mjs.map +1 -1
- package/dist/esm/toolbar/LinkDialog.native.js +84 -80
- package/dist/esm/toolbar/LinkDialog.native.js.map +1 -1
- package/dist/esm/toolbar/ListPicker.mjs +33 -44
- package/dist/esm/toolbar/ListPicker.mjs.map +1 -1
- package/dist/esm/toolbar/ListPicker.native.js +44 -45
- package/dist/esm/toolbar/ListPicker.native.js.map +1 -1
- package/dist/esm/toolbar/MathBubble.mjs +134 -0
- package/dist/esm/toolbar/MathBubble.mjs.map +1 -0
- package/dist/esm/toolbar/MathBubble.native.js +141 -0
- package/dist/esm/toolbar/MathBubble.native.js.map +1 -0
- package/dist/esm/toolbar/MoreDropdown.mjs +50 -97
- package/dist/esm/toolbar/MoreDropdown.mjs.map +1 -1
- package/dist/esm/toolbar/MoreDropdown.native.js +72 -97
- package/dist/esm/toolbar/MoreDropdown.native.js.map +1 -1
- package/dist/esm/toolbar/StatusBar.mjs +19 -10
- package/dist/esm/toolbar/StatusBar.mjs.map +1 -1
- package/dist/esm/toolbar/StatusBar.native.js +19 -10
- package/dist/esm/toolbar/StatusBar.native.js.map +1 -1
- package/dist/esm/toolbar/TableBubble.mjs +77 -95
- package/dist/esm/toolbar/TableBubble.mjs.map +1 -1
- package/dist/esm/toolbar/TableBubble.native.js +73 -71
- package/dist/esm/toolbar/TableBubble.native.js.map +1 -1
- package/dist/esm/toolbar/ToolbarButton.mjs +87 -22
- package/dist/esm/toolbar/ToolbarButton.mjs.map +1 -1
- package/dist/esm/toolbar/ToolbarButton.native.js +14 -4
- package/dist/esm/toolbar/ToolbarButton.native.js.map +1 -1
- package/dist/esm/toolbar/icons.mjs +109 -469
- package/dist/esm/toolbar/icons.mjs.map +1 -1
- package/dist/esm/toolbar/shortcuts.mjs +73 -24
- package/dist/esm/toolbar/shortcuts.mjs.map +1 -1
- package/dist/esm/toolbar/shortcuts.native.js +73 -24
- package/dist/esm/toolbar/shortcuts.native.js.map +1 -1
- package/dist/esm/toolbar/useHorizontalScroll.mjs +25 -6
- package/dist/esm/toolbar/useHorizontalScroll.mjs.map +1 -1
- package/dist/esm/toolbar/useHorizontalScroll.native.js +25 -6
- package/dist/esm/toolbar/useHorizontalScroll.native.js.map +1 -1
- package/dist/esm/toolbar/useRovingFocus.mjs +55 -0
- package/dist/esm/toolbar/useRovingFocus.mjs.map +1 -0
- package/dist/esm/toolbar/useRovingFocus.native.js +85 -0
- package/dist/esm/toolbar/useRovingFocus.native.js.map +1 -0
- package/dist/esm/types.mjs.map +1 -1
- package/dist/esm/types.native.js.map +1 -1
- package/dist/jsx/RichEditor.mjs +85 -10
- package/dist/jsx/RichEditor.mjs.map +1 -1
- package/dist/jsx/RichEditor.native.js +422 -35
- package/dist/jsx/RichEditor.native.js.map +1 -1
- package/dist/jsx/RichTextEditor/index.mjs +18 -2
- package/dist/jsx/RichTextEditor/index.mjs.map +1 -1
- package/dist/jsx/RichTextEditor/index.native.js +18 -2
- package/dist/jsx/RichTextEditor/index.native.js.map +1 -1
- package/dist/jsx/constants.mjs +47 -29
- package/dist/jsx/constants.mjs.map +1 -1
- package/dist/jsx/constants.native.js +59 -29
- package/dist/jsx/constants.native.js.map +1 -1
- package/dist/jsx/editor/BlockDragHandle.mjs +22 -7
- package/dist/jsx/editor/BlockDragHandle.mjs.map +1 -1
- package/dist/jsx/editor/BlockDragHandle.native.js +41 -7
- package/dist/jsx/editor/BlockDragHandle.native.js.map +1 -1
- package/dist/jsx/editor/SlashCommands.mjs +250 -294
- package/dist/jsx/editor/SlashCommands.mjs.map +1 -1
- package/dist/jsx/editor/SlashCommands.native.js +306 -340
- package/dist/jsx/editor/SlashCommands.native.js.map +1 -1
- package/dist/jsx/editor/TentapEditor.native.js +44 -12
- package/dist/jsx/editor/TentapEditor.native.js.map +1 -1
- package/dist/jsx/editor/TiptapEditor.mjs +142 -35
- package/dist/jsx/editor/TiptapEditor.mjs.map +1 -1
- package/dist/jsx/editor/TiptapEditor.native.js +153 -33
- package/dist/jsx/editor/TiptapEditor.native.js.map +1 -1
- package/dist/jsx/editor/blockAnchor.mjs +18 -0
- package/dist/jsx/editor/blockAnchor.mjs.map +1 -0
- package/dist/jsx/editor/blockAnchor.native.js +68 -0
- package/dist/jsx/editor/blockAnchor.native.js.map +1 -0
- package/dist/jsx/editor/codeBlockPreview.mjs +190 -0
- package/dist/jsx/editor/codeBlockPreview.mjs.map +1 -0
- package/dist/jsx/editor/codeBlockPreview.native.js +265 -0
- package/dist/jsx/editor/codeBlockPreview.native.js.map +1 -0
- package/dist/jsx/editor/editorStyles.mjs +203 -34
- package/dist/jsx/editor/editorStyles.mjs.map +1 -1
- package/dist/jsx/editor/editorStyles.native.js +203 -34
- package/dist/jsx/editor/editorStyles.native.js.map +1 -1
- package/dist/jsx/editor/emoji.mjs +88 -0
- package/dist/jsx/editor/emoji.mjs.map +1 -0
- package/dist/jsx/editor/emoji.native.js +184 -0
- package/dist/jsx/editor/emoji.native.js.map +1 -0
- package/dist/jsx/editor/lazyKatex.mjs +40 -0
- package/dist/jsx/editor/lazyKatex.mjs.map +1 -0
- package/dist/jsx/editor/lazyKatex.native.js +117 -0
- package/dist/jsx/editor/lazyKatex.native.js.map +1 -0
- package/dist/jsx/editor/markdown.mjs +179 -0
- package/dist/jsx/editor/markdown.mjs.map +1 -0
- package/dist/jsx/editor/markdown.native.js +278 -0
- package/dist/jsx/editor/markdown.native.js.map +1 -0
- package/dist/jsx/editor/mathematics.mjs +142 -0
- package/dist/jsx/editor/mathematics.mjs.map +1 -0
- package/dist/jsx/editor/mathematics.native.js +202 -0
- package/dist/jsx/editor/mathematics.native.js.map +1 -0
- package/dist/jsx/editor/media.mjs +113 -0
- package/dist/jsx/editor/media.mjs.map +1 -0
- package/dist/jsx/editor/media.native.js +172 -0
- package/dist/jsx/editor/media.native.js.map +1 -0
- package/dist/jsx/editor/mentions.mjs +37 -0
- package/dist/jsx/editor/mentions.mjs.map +1 -0
- package/dist/jsx/editor/mentions.native.js +84 -0
- package/dist/jsx/editor/mentions.native.js.map +1 -0
- package/dist/jsx/editor/pasteCleanup.mjs +57 -0
- package/dist/jsx/editor/pasteCleanup.mjs.map +1 -0
- package/dist/jsx/editor/pasteCleanup.native.js +175 -0
- package/dist/jsx/editor/pasteCleanup.native.js.map +1 -0
- package/dist/jsx/editor/suggestionPopup.mjs +268 -0
- package/dist/jsx/editor/suggestionPopup.mjs.map +1 -0
- package/dist/jsx/editor/suggestionPopup.native.js +327 -0
- package/dist/jsx/editor/suggestionPopup.native.js.map +1 -0
- package/dist/jsx/preview.mjs +236 -0
- package/dist/jsx/preview.mjs.map +1 -0
- package/dist/jsx/preview.native.js +294 -0
- package/dist/jsx/preview.native.js.map +1 -0
- package/dist/jsx/shared/t.mjs +17 -0
- package/dist/jsx/shared/t.mjs.map +1 -0
- package/dist/jsx/shared/t.native.js +56 -0
- package/dist/jsx/shared/t.native.js.map +1 -0
- package/dist/jsx/shared/url.mjs +10 -0
- package/dist/jsx/shared/url.mjs.map +1 -0
- package/dist/jsx/shared/url.native.js +38 -0
- package/dist/jsx/shared/url.native.js.map +1 -0
- package/dist/jsx/styled.mjs +13 -6
- package/dist/jsx/styled.mjs.map +1 -1
- package/dist/jsx/styled.native.js +13 -6
- package/dist/jsx/styled.native.js.map +1 -1
- package/dist/jsx/toolbar/BubbleToolbar.mjs +11 -9
- package/dist/jsx/toolbar/BubbleToolbar.mjs.map +1 -1
- package/dist/jsx/toolbar/BubbleToolbar.native.js +10 -8
- package/dist/jsx/toolbar/BubbleToolbar.native.js.map +1 -1
- package/dist/jsx/toolbar/CodeBlockBubble.mjs +60 -24
- package/dist/jsx/toolbar/CodeBlockBubble.mjs.map +1 -1
- package/dist/jsx/toolbar/CodeBlockBubble.native.js +71 -25
- package/dist/jsx/toolbar/CodeBlockBubble.native.js.map +1 -1
- package/dist/jsx/toolbar/ColorPicker.mjs +21 -56
- package/dist/jsx/toolbar/ColorPicker.mjs.map +1 -1
- package/dist/jsx/toolbar/ColorPicker.native.js +81 -179
- package/dist/jsx/toolbar/ColorPicker.native.js.map +1 -1
- package/dist/jsx/toolbar/FixedToolbar.mjs +34 -11
- package/dist/jsx/toolbar/FixedToolbar.mjs.map +1 -1
- package/dist/jsx/toolbar/FixedToolbar.native.js +46 -54
- package/dist/jsx/toolbar/FixedToolbar.native.js.map +1 -1
- package/dist/jsx/toolbar/HeadingPicker.mjs +34 -41
- package/dist/jsx/toolbar/HeadingPicker.mjs.map +1 -1
- package/dist/jsx/toolbar/HeadingPicker.native.js +61 -51
- package/dist/jsx/toolbar/HeadingPicker.native.js.map +1 -1
- package/dist/jsx/toolbar/ImageBubble.mjs +20 -43
- package/dist/jsx/toolbar/ImageBubble.mjs.map +1 -1
- package/dist/jsx/toolbar/ImageBubble.native.js +20 -43
- package/dist/jsx/toolbar/ImageBubble.native.js.map +1 -1
- package/dist/jsx/toolbar/ImageDialog.mjs +5 -4
- package/dist/jsx/toolbar/ImageDialog.mjs.map +1 -1
- package/dist/jsx/toolbar/ImageDialog.native.js +76 -65
- package/dist/jsx/toolbar/ImageDialog.native.js.map +1 -1
- package/dist/jsx/toolbar/LinkBubble.mjs +23 -70
- package/dist/jsx/toolbar/LinkBubble.mjs.map +1 -1
- package/dist/jsx/toolbar/LinkBubble.native.js +23 -70
- package/dist/jsx/toolbar/LinkBubble.native.js.map +1 -1
- package/dist/jsx/toolbar/LinkDialog.mjs +17 -16
- package/dist/jsx/toolbar/LinkDialog.mjs.map +1 -1
- package/dist/jsx/toolbar/LinkDialog.native.js +86 -83
- package/dist/jsx/toolbar/LinkDialog.native.js.map +1 -1
- package/dist/jsx/toolbar/ListPicker.mjs +33 -44
- package/dist/jsx/toolbar/ListPicker.mjs.map +1 -1
- package/dist/jsx/toolbar/ListPicker.native.js +43 -44
- package/dist/jsx/toolbar/ListPicker.native.js.map +1 -1
- package/dist/jsx/toolbar/MathBubble.mjs +134 -0
- package/dist/jsx/toolbar/MathBubble.mjs.map +1 -0
- package/dist/jsx/toolbar/MathBubble.native.js +169 -0
- package/dist/jsx/toolbar/MathBubble.native.js.map +1 -0
- package/dist/jsx/toolbar/MoreDropdown.mjs +50 -97
- package/dist/jsx/toolbar/MoreDropdown.mjs.map +1 -1
- package/dist/jsx/toolbar/MoreDropdown.native.js +73 -98
- package/dist/jsx/toolbar/MoreDropdown.native.js.map +1 -1
- package/dist/jsx/toolbar/StatusBar.mjs +19 -10
- package/dist/jsx/toolbar/StatusBar.mjs.map +1 -1
- package/dist/jsx/toolbar/StatusBar.native.js +19 -10
- package/dist/jsx/toolbar/StatusBar.native.js.map +1 -1
- package/dist/jsx/toolbar/TableBubble.mjs +77 -95
- package/dist/jsx/toolbar/TableBubble.mjs.map +1 -1
- package/dist/jsx/toolbar/TableBubble.native.js +73 -71
- package/dist/jsx/toolbar/TableBubble.native.js.map +1 -1
- package/dist/jsx/toolbar/ToolbarButton.mjs +87 -22
- package/dist/jsx/toolbar/ToolbarButton.mjs.map +1 -1
- package/dist/jsx/toolbar/ToolbarButton.native.js +14 -4
- package/dist/jsx/toolbar/ToolbarButton.native.js.map +1 -1
- package/dist/jsx/toolbar/icons.mjs +109 -469
- package/dist/jsx/toolbar/icons.mjs.map +1 -1
- package/dist/jsx/toolbar/shortcuts.mjs +73 -24
- package/dist/jsx/toolbar/shortcuts.mjs.map +1 -1
- package/dist/jsx/toolbar/shortcuts.native.js +73 -24
- package/dist/jsx/toolbar/shortcuts.native.js.map +1 -1
- package/dist/jsx/toolbar/useHorizontalScroll.mjs +25 -6
- package/dist/jsx/toolbar/useHorizontalScroll.mjs.map +1 -1
- package/dist/jsx/toolbar/useHorizontalScroll.native.js +25 -5
- package/dist/jsx/toolbar/useHorizontalScroll.native.js.map +1 -1
- package/dist/jsx/toolbar/useRovingFocus.mjs +55 -0
- package/dist/jsx/toolbar/useRovingFocus.mjs.map +1 -0
- package/dist/jsx/toolbar/useRovingFocus.native.js +113 -0
- package/dist/jsx/toolbar/useRovingFocus.native.js.map +1 -0
- package/dist/jsx/types.mjs.map +1 -1
- package/dist/jsx/types.native.js.map +1 -1
- package/package.json +28 -13
- package/src/RichEditor.native.tsx +451 -49
- package/src/RichEditor.stories.tsx +158 -0
- package/src/RichEditor.tsx +121 -7
- package/src/RichTextEditor/index.tsx +41 -3
- package/src/RichTextEditor/richTextEditor.spec.tsx +11 -4
- package/src/constants.ts +86 -24
- package/src/editor/BlockDragHandle.ts +30 -5
- package/src/editor/SlashCommands.tsx +228 -293
- package/src/editor/TentapEditor.native.tsx +68 -17
- package/src/editor/TiptapEditor.tsx +187 -22
- package/src/editor/blockAnchor.spec.ts +70 -0
- package/src/editor/blockAnchor.ts +42 -0
- package/src/editor/codeBlockPreview.spec.ts +144 -0
- package/src/editor/codeBlockPreview.ts +266 -0
- package/src/editor/css.d.ts +2 -0
- package/src/editor/details.spec.ts +48 -0
- package/src/editor/editorStyles.spec.ts +25 -0
- package/src/editor/editorStyles.ts +218 -34
- package/src/editor/emoji.spec.ts +88 -0
- package/src/editor/emoji.ts +147 -0
- package/src/editor/emojilib.d.ts +16 -0
- package/src/editor/lazyKatex.spec.ts +38 -0
- package/src/editor/lazyKatex.ts +68 -0
- package/src/editor/markdown.spec.ts +196 -0
- package/src/editor/markdown.ts +249 -0
- package/src/editor/mathematics.spec.ts +97 -0
- package/src/editor/mathematics.ts +179 -0
- package/src/editor/media.spec.ts +121 -0
- package/src/editor/media.ts +133 -0
- package/src/editor/mentions.spec.ts +41 -0
- package/src/editor/mentions.ts +55 -0
- package/src/editor/pasteCleanup.spec.ts +84 -0
- package/src/editor/pasteCleanup.ts +124 -0
- package/src/editor/suggestionPopup.spec.tsx +105 -0
- package/src/editor/suggestionPopup.tsx +414 -0
- package/src/editor/tiptapEditor.spec.tsx +15 -8
- package/src/exports.spec.ts +4 -2
- package/src/index.ts +7 -1
- package/src/integration.spec.tsx +38 -9
- package/src/preview.spec.ts +130 -0
- package/src/preview.ts +287 -0
- package/src/richEditor.spec.tsx +10 -3
- package/src/shared/t.ts +25 -0
- package/src/shared/url.ts +16 -0
- package/src/styled.ts +13 -6
- package/src/toolbar/BubbleToolbar.tsx +11 -8
- package/src/toolbar/CodeBlockBubble.tsx +66 -28
- package/src/toolbar/ColorPicker.native.tsx +126 -0
- package/src/toolbar/ColorPicker.tsx +23 -67
- package/src/toolbar/FixedToolbar.native.tsx +51 -51
- package/src/toolbar/FixedToolbar.tsx +54 -10
- package/src/toolbar/HeadingPicker.tsx +46 -38
- package/src/toolbar/ImageBubble.tsx +26 -44
- package/src/toolbar/ImageDialog.native.tsx +97 -0
- package/src/toolbar/ImageDialog.tsx +5 -4
- package/src/toolbar/LinkBubble.tsx +27 -64
- package/src/toolbar/LinkDialog.native.tsx +117 -0
- package/src/toolbar/LinkDialog.tsx +28 -24
- package/src/toolbar/ListPicker.tsx +47 -43
- package/src/toolbar/MathBubble.tsx +140 -0
- package/src/toolbar/MoreDropdown.tsx +53 -60
- package/src/toolbar/StatusBar.tsx +13 -8
- package/src/toolbar/TableBubble.tsx +82 -94
- package/src/toolbar/ToolbarButton.native.tsx +14 -4
- package/src/toolbar/ToolbarButton.tsx +98 -19
- package/src/toolbar/bubbleToolbar.spec.tsx +2 -1
- package/src/toolbar/fixedToolbar.spec.tsx +4 -2
- package/src/toolbar/icons.tsx +113 -323
- package/src/toolbar/shortcuts.ts +77 -24
- package/src/toolbar/toolbarPrimitives.spec.tsx +29 -1
- package/src/toolbar/toolbarSubComponents.spec.tsx +4 -2
- package/src/toolbar/useHorizontalScroll.spec.ts +67 -0
- package/src/toolbar/useHorizontalScroll.tsx +39 -12
- package/src/toolbar/useRovingFocus.spec.tsx +100 -0
- package/src/toolbar/useRovingFocus.ts +82 -0
- package/src/types.spec.ts +40 -1
- package/src/types.ts +28 -0
- package/types/RichEditor.d.ts +51 -0
- package/types/RichEditor.d.ts.map +1 -0
- package/types/RichEditor.native.d.ts +59 -0
- package/types/RichEditor.native.d.ts.map +1 -0
- package/types/RichTextEditor/index.d.ts +71 -0
- package/types/RichTextEditor/index.d.ts.map +1 -0
- package/types/constants.d.ts +49 -0
- package/types/constants.d.ts.map +1 -0
- package/types/context.d.ts +10 -0
- package/types/context.d.ts.map +1 -0
- package/types/editor/BlockDragHandle.d.ts +8 -0
- package/types/editor/BlockDragHandle.d.ts.map +1 -0
- package/types/editor/MarkdownPaste.d.ts +8 -0
- package/types/editor/MarkdownPaste.d.ts.map +1 -0
- package/types/editor/SlashCommands.d.ts +24 -0
- package/types/editor/SlashCommands.d.ts.map +1 -0
- package/types/editor/TentapEditor.native.d.ts +21 -0
- package/types/editor/TentapEditor.native.d.ts.map +1 -0
- package/types/editor/TiptapEditor.d.ts +24 -0
- package/types/editor/TiptapEditor.d.ts.map +1 -0
- package/types/editor/blockAnchor.d.ts +25 -0
- package/types/editor/blockAnchor.d.ts.map +1 -0
- package/types/editor/codeBlockPreview.d.ts +51 -0
- package/types/editor/codeBlockPreview.d.ts.map +1 -0
- package/types/editor/editorStyles.d.ts +25 -0
- package/types/editor/editorStyles.d.ts.map +1 -0
- package/types/editor/emoji.d.ts +45 -0
- package/types/editor/emoji.d.ts.map +1 -0
- package/types/editor/index.d.ts +11 -0
- package/types/editor/index.d.ts.map +1 -0
- package/types/editor/lazyKatex.d.ts +33 -0
- package/types/editor/lazyKatex.d.ts.map +1 -0
- package/types/editor/markdown.d.ts +24 -0
- package/types/editor/markdown.d.ts.map +1 -0
- package/types/editor/mathematics.d.ts +44 -0
- package/types/editor/mathematics.d.ts.map +1 -0
- package/types/editor/media.d.ts +32 -0
- package/types/editor/media.d.ts.map +1 -0
- package/types/editor/mentions.d.ts +15 -0
- package/types/editor/mentions.d.ts.map +1 -0
- package/types/editor/pasteCleanup.d.ts +24 -0
- package/types/editor/pasteCleanup.d.ts.map +1 -0
- package/types/editor/suggestionPopup.d.ts +113 -0
- package/types/editor/suggestionPopup.d.ts.map +1 -0
- package/types/editor/types.d.ts +80 -0
- package/types/editor/types.d.ts.map +1 -0
- package/types/editor/useEditorState.d.ts +19 -0
- package/types/editor/useEditorState.d.ts.map +1 -0
- package/types/index.d.ts +11 -0
- package/types/index.d.ts.map +1 -0
- package/types/preview.d.ts +44 -0
- package/types/preview.d.ts.map +1 -0
- package/types/shared/t.d.ts +10 -0
- package/types/shared/t.d.ts.map +1 -0
- package/types/shared/url.d.ts +9 -0
- package/types/shared/url.d.ts.map +1 -0
- package/types/styled.d.ts +40 -0
- package/types/styled.d.ts.map +1 -0
- package/types/toolbar/BubbleToolbar.d.ts +23 -0
- package/types/toolbar/BubbleToolbar.d.ts.map +1 -0
- package/types/toolbar/CodeBlockBubble.d.ts +10 -0
- package/types/toolbar/CodeBlockBubble.d.ts.map +1 -0
- package/types/toolbar/ColorPicker.d.ts +15 -0
- package/types/toolbar/ColorPicker.d.ts.map +1 -0
- package/types/toolbar/ColorPicker.native.d.ts +20 -0
- package/types/toolbar/ColorPicker.native.d.ts.map +1 -0
- package/types/toolbar/FixedToolbar.d.ts +32 -0
- package/types/toolbar/FixedToolbar.d.ts.map +1 -0
- package/types/toolbar/FixedToolbar.native.d.ts +30 -0
- package/types/toolbar/FixedToolbar.native.d.ts.map +1 -0
- package/types/toolbar/HeadingPicker.d.ts +14 -0
- package/types/toolbar/HeadingPicker.d.ts.map +1 -0
- package/types/toolbar/ImageBubble.d.ts +10 -0
- package/types/toolbar/ImageBubble.d.ts.map +1 -0
- package/types/toolbar/ImageDialog.d.ts +12 -0
- package/types/toolbar/ImageDialog.d.ts.map +1 -0
- package/types/toolbar/ImageDialog.native.d.ts +15 -0
- package/types/toolbar/ImageDialog.native.d.ts.map +1 -0
- package/types/toolbar/LinkBubble.d.ts +10 -0
- package/types/toolbar/LinkBubble.d.ts.map +1 -0
- package/types/toolbar/LinkDialog.d.ts +20 -0
- package/types/toolbar/LinkDialog.d.ts.map +1 -0
- package/types/toolbar/LinkDialog.native.d.ts +18 -0
- package/types/toolbar/LinkDialog.native.d.ts.map +1 -0
- package/types/toolbar/ListPicker.d.ts +14 -0
- package/types/toolbar/ListPicker.d.ts.map +1 -0
- package/types/toolbar/MathBubble.d.ts +11 -0
- package/types/toolbar/MathBubble.d.ts.map +1 -0
- package/types/toolbar/MoreDropdown.d.ts +13 -0
- package/types/toolbar/MoreDropdown.d.ts.map +1 -0
- package/types/toolbar/ResizeHandle.d.ts +11 -0
- package/types/toolbar/ResizeHandle.d.ts.map +1 -0
- package/types/toolbar/StatusBar.d.ts +11 -0
- package/types/toolbar/StatusBar.d.ts.map +1 -0
- package/types/toolbar/TableBubble.d.ts +10 -0
- package/types/toolbar/TableBubble.d.ts.map +1 -0
- package/types/toolbar/ToolbarButton.d.ts +35 -0
- package/types/toolbar/ToolbarButton.d.ts.map +1 -0
- package/types/toolbar/ToolbarButton.native.d.ts +30 -0
- package/types/toolbar/ToolbarButton.native.d.ts.map +1 -0
- package/types/toolbar/ToolbarGroup.d.ts +14 -0
- package/types/toolbar/ToolbarGroup.d.ts.map +1 -0
- package/types/toolbar/icons.d.ts +52 -0
- package/types/toolbar/icons.d.ts.map +1 -0
- package/types/toolbar/icons.native.d.ts +41 -0
- package/types/toolbar/icons.native.d.ts.map +1 -0
- package/types/toolbar/shortcuts.d.ts +34 -0
- package/types/toolbar/shortcuts.d.ts.map +1 -0
- package/types/toolbar/useHorizontalScroll.d.ts +43 -0
- package/types/toolbar/useHorizontalScroll.d.ts.map +1 -0
- package/types/toolbar/useRovingFocus.d.ts +10 -0
- package/types/toolbar/useRovingFocus.d.ts.map +1 -0
- package/types/types.d.ts +125 -0
- package/types/types.d.ts.map +1 -0
- package/dist/cjs/RichEditor.stories.cjs +0 -327
- package/dist/cjs/RichEditor.stories.native.js +0 -342
- package/dist/cjs/RichEditor.stories.native.js.map +0 -1
- package/dist/esm/RichEditor.stories.mjs +0 -291
- package/dist/esm/RichEditor.stories.mjs.map +0 -1
- package/dist/esm/RichEditor.stories.native.js +0 -303
- package/dist/esm/RichEditor.stories.native.js.map +0 -1
- package/dist/jsx/RichEditor.stories.mjs +0 -291
- package/dist/jsx/RichEditor.stories.mjs.map +0 -1
- package/dist/jsx/RichEditor.stories.native.js +0 -342
- package/dist/jsx/RichEditor.stories.native.js.map +0 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste sanitizer for HTML clipboard payloads from Google Docs and
|
|
3
|
+
* Microsoft Word/Outlook.
|
|
4
|
+
*
|
|
5
|
+
* Both sources wrap content in junk that either breaks ProseMirror parsing
|
|
6
|
+
* or smuggles presentation into the document:
|
|
7
|
+
* - Google Docs wraps the entire fragment in
|
|
8
|
+
* `<b style="font-weight:normal" id="docs-internal-guid-...">` (which
|
|
9
|
+
* ProseMirror would read as bold) and inlines font/size styles on spans.
|
|
10
|
+
* - Word ships `<o:p>` tags, `Mso*` classes, `mso-*` style declarations,
|
|
11
|
+
* XML islands, and conditional comments.
|
|
12
|
+
*
|
|
13
|
+
* The cleanup keeps semantics (b/strong/i/em/u/lists/headings/links and
|
|
14
|
+
* color/background-color styles the editor actually supports) and drops
|
|
15
|
+
* the rest. Non-office HTML passes through untouched.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const OFFICE_SIGNATURES = [
|
|
19
|
+
"docs-internal-guid",
|
|
20
|
+
"urn:schemas-microsoft-com",
|
|
21
|
+
"MsoNormal",
|
|
22
|
+
"mso-",
|
|
23
|
+
"<o:p>",
|
|
24
|
+
"office:office",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/** True when the clipboard HTML comes from Google Docs or Microsoft Office */
|
|
28
|
+
export function isOfficeHtml(html: string): boolean {
|
|
29
|
+
return OFFICE_SIGNATURES.some((sig) => html.includes(sig));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Style declarations the editor supports (everything else is junk) */
|
|
33
|
+
const KEPT_STYLES = new Set([
|
|
34
|
+
"color",
|
|
35
|
+
"background-color",
|
|
36
|
+
// Docs/Word mark bold/italic/underline/strike with span styles rather
|
|
37
|
+
// than semantic tags; ProseMirror parses these into real marks.
|
|
38
|
+
"font-weight",
|
|
39
|
+
"font-style",
|
|
40
|
+
"text-decoration",
|
|
41
|
+
"text-decoration-line",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
function cleanElement(el: Element): void {
|
|
45
|
+
// Word XML-namespaced elements (<o:p>, <w:sdt>, ...) contribute nothing
|
|
46
|
+
if (el.tagName.includes(":")) {
|
|
47
|
+
el.remove();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (el.hasAttribute("class")) el.removeAttribute("class");
|
|
52
|
+
if (el.hasAttribute("lang")) el.removeAttribute("lang");
|
|
53
|
+
if (el.hasAttribute("id")) el.removeAttribute("id");
|
|
54
|
+
|
|
55
|
+
if (el.hasAttribute("style")) {
|
|
56
|
+
// Parse the attribute text directly (not CSSStyleDeclaration) so the
|
|
57
|
+
// result is identical across browsers and DOM test environments.
|
|
58
|
+
const declarations = (el.getAttribute("style") ?? "")
|
|
59
|
+
.split(";")
|
|
60
|
+
.map((decl) => decl.trim())
|
|
61
|
+
.filter((decl) => decl.includes(":"));
|
|
62
|
+
const kept: string[] = [];
|
|
63
|
+
for (const decl of declarations) {
|
|
64
|
+
const colon = decl.indexOf(":");
|
|
65
|
+
const prop = decl.slice(0, colon).trim().toLowerCase();
|
|
66
|
+
const value = decl.slice(colon + 1).trim();
|
|
67
|
+
if (!KEPT_STYLES.has(prop)) continue;
|
|
68
|
+
// Office emits default inks explicitly; dropping them keeps content
|
|
69
|
+
// on theme text color instead of hardcoded near-black
|
|
70
|
+
if (prop === "color" && /^(rgb\(0,\s*0,\s*0\)|#000000|#000|windowtext)$/i.test(value)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (
|
|
74
|
+
prop === "background-color" &&
|
|
75
|
+
/^(transparent|#ffffff|#fff|rgb\(255,\s*255,\s*255\))$/i.test(value)
|
|
76
|
+
) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// Non-emphasis values are the office default state, not authored marks
|
|
80
|
+
if (prop === "font-weight" && !/^(bold(er)?|[5-9]\d\d)$/i.test(value)) continue;
|
|
81
|
+
if (prop === "font-style" && !/^(italic|oblique)/i.test(value)) continue;
|
|
82
|
+
if (
|
|
83
|
+
(prop === "text-decoration" || prop === "text-decoration-line") &&
|
|
84
|
+
!/(underline|line-through)/i.test(value)
|
|
85
|
+
) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
kept.push(`${prop}: ${value}`);
|
|
89
|
+
}
|
|
90
|
+
if (kept.length > 0) el.setAttribute("style", kept.join("; "));
|
|
91
|
+
else el.removeAttribute("style");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const child of Array.from(el.children)) cleanElement(child);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Sanitize office-suite clipboard HTML. Non-office HTML is returned as-is
|
|
99
|
+
* (regular web copy already parses cleanly).
|
|
100
|
+
*/
|
|
101
|
+
export function cleanPastedHtml(html: string): string {
|
|
102
|
+
if (typeof document === "undefined" || !isOfficeHtml(html)) return html;
|
|
103
|
+
|
|
104
|
+
// Strip XML islands and conditional comments before parsing
|
|
105
|
+
const source = html
|
|
106
|
+
.replace(/<xml>[\s\S]*?<\/xml>/gi, "")
|
|
107
|
+
.replace(/<!--\[if[\s\S]*?<!\[endif\]-->/gi, "")
|
|
108
|
+
.replace(/<!--StartFragment-->|<!--EndFragment-->/gi, "");
|
|
109
|
+
|
|
110
|
+
const doc = new DOMParser().parseFromString(source, "text/html");
|
|
111
|
+
doc.querySelectorAll("style, meta, link, script, title").forEach((el) => el.remove());
|
|
112
|
+
|
|
113
|
+
// Google Docs: unwrap the non-bold <b> guid wrapper so content is not bold
|
|
114
|
+
for (const b of Array.from(doc.body.querySelectorAll("b"))) {
|
|
115
|
+
const weight = (b as HTMLElement).style.fontWeight;
|
|
116
|
+
if (weight === "normal" || weight === "400") {
|
|
117
|
+
b.replaceWith(...Array.from(b.childNodes));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (const child of Array.from(doc.body.children)) cleanElement(child);
|
|
122
|
+
|
|
123
|
+
return doc.body.innerHTML;
|
|
124
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { act, createRef } from "react";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import {
|
|
5
|
+
SuggestionList,
|
|
6
|
+
fallbackSuggestionChrome,
|
|
7
|
+
getSuggestionChrome,
|
|
8
|
+
type SuggestionListRef,
|
|
9
|
+
type SuggestionRow,
|
|
10
|
+
} from "./suggestionPopup";
|
|
11
|
+
|
|
12
|
+
const rows: SuggestionRow[] = [
|
|
13
|
+
{ key: "a", title: "Alpha", description: "first" },
|
|
14
|
+
{ key: "b", title: "Beta", description: "second" },
|
|
15
|
+
{ key: "c", title: "Gamma", description: "third" },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const chrome = { ...fallbackSuggestionChrome, rowPaddingX: 12 };
|
|
19
|
+
|
|
20
|
+
function renderList(onSelect = vi.fn()) {
|
|
21
|
+
const ref = createRef<SuggestionListRef>();
|
|
22
|
+
const utils = render(
|
|
23
|
+
<SuggestionList
|
|
24
|
+
ref={ref}
|
|
25
|
+
rows={rows}
|
|
26
|
+
chrome={chrome}
|
|
27
|
+
emptyLabel="No results"
|
|
28
|
+
onSelect={onSelect}
|
|
29
|
+
/>,
|
|
30
|
+
);
|
|
31
|
+
return { ref, onSelect, ...utils };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("SuggestionList", () => {
|
|
35
|
+
it("renders one option per row with LC-16 menu-row geometry", () => {
|
|
36
|
+
const { container } = renderList();
|
|
37
|
+
const options = container.querySelectorAll('[role="option"]');
|
|
38
|
+
expect(options.length).toBe(3);
|
|
39
|
+
const style = (options[0] as HTMLElement).style;
|
|
40
|
+
// menuRowFrame-derived horizontal padding, flat corners, full width
|
|
41
|
+
expect(style.padding).toBe("8px 12px");
|
|
42
|
+
expect(style.borderRadius).toBe("0px");
|
|
43
|
+
expect(style.width).toBe("100%");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("marks the first row selected and navigates with arrows (wrapping)", () => {
|
|
47
|
+
const { ref, container } = renderList();
|
|
48
|
+
const selected = () =>
|
|
49
|
+
Array.from(container.querySelectorAll('[role="option"]')).findIndex(
|
|
50
|
+
(el) => el.getAttribute("aria-selected") === "true",
|
|
51
|
+
);
|
|
52
|
+
expect(selected()).toBe(0);
|
|
53
|
+
act(() => {
|
|
54
|
+
ref.current!.onKeyDown({ event: new KeyboardEvent("keydown", { key: "ArrowDown" }) });
|
|
55
|
+
});
|
|
56
|
+
expect(selected()).toBe(1);
|
|
57
|
+
act(() => {
|
|
58
|
+
ref.current!.onKeyDown({ event: new KeyboardEvent("keydown", { key: "ArrowUp" }) });
|
|
59
|
+
ref.current!.onKeyDown({ event: new KeyboardEvent("keydown", { key: "ArrowUp" }) });
|
|
60
|
+
});
|
|
61
|
+
expect(selected()).toBe(2);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("selects with Enter and Tab", () => {
|
|
65
|
+
const { ref, onSelect } = renderList();
|
|
66
|
+
act(() => {
|
|
67
|
+
ref.current!.onKeyDown({ event: new KeyboardEvent("keydown", { key: "ArrowDown" }) });
|
|
68
|
+
});
|
|
69
|
+
let handled = false;
|
|
70
|
+
act(() => {
|
|
71
|
+
handled = ref.current!.onKeyDown({
|
|
72
|
+
event: new KeyboardEvent("keydown", { key: "Enter" }),
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
expect(handled).toBe(true);
|
|
76
|
+
expect(onSelect).toHaveBeenCalledWith(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("selects on click", () => {
|
|
80
|
+
const { container, onSelect } = renderList();
|
|
81
|
+
const options = container.querySelectorAll('[role="option"]');
|
|
82
|
+
(options[2] as HTMLElement).click();
|
|
83
|
+
expect(onSelect).toHaveBeenCalledWith(2);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("shows the empty label when there are no rows", () => {
|
|
87
|
+
const { container } = render(
|
|
88
|
+
<SuggestionList rows={[]} chrome={chrome} emptyLabel="No results" onSelect={vi.fn()} />,
|
|
89
|
+
);
|
|
90
|
+
expect(container.textContent).toContain("No results");
|
|
91
|
+
expect(container.querySelectorAll('[role="option"]').length).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("getSuggestionChrome", () => {
|
|
96
|
+
it("reads the chrome pushed by the editor host", () => {
|
|
97
|
+
const editor = { storage: { suggestionChrome: { value: chrome } } };
|
|
98
|
+
expect(getSuggestionChrome(editor)).toBe(chrome);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("falls back to the neutral chrome before the host pushes values", () => {
|
|
102
|
+
expect(getSuggestionChrome(null)).toBe(fallbackSuggestionChrome);
|
|
103
|
+
expect(getSuggestionChrome({ storage: {} })).toBe(fallbackSuggestionChrome);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared suggestion popup for editor typeahead menus (slash commands and
|
|
3
|
+
* @ mentions).
|
|
4
|
+
*
|
|
5
|
+
* One implementation (LC-16): both menus render the same row anatomy with
|
|
6
|
+
* the shared menu-row geometry (SP-EDGE -- the container owns only its
|
|
7
|
+
* border, rows own all padding and span edge-to-edge, matching
|
|
8
|
+
* SelectRow / DropdownMenuItemFrame / MentionSuggestionItem: 12px
|
|
9
|
+
* horizontal x 8px vertical padding, 8px in-row gap, flat corners).
|
|
10
|
+
*
|
|
11
|
+
* The popup is portaled to document.body (it must escape the editor frame
|
|
12
|
+
* and the fullscreen z-index), which puts it OUTSIDE the Tamagui theme
|
|
13
|
+
* scope -- so no Tamagui components and no raw CSS fallbacks. Every color
|
|
14
|
+
* and structural role comes from `SuggestionChrome`, resolved from the
|
|
15
|
+
* live theme + knobs by the editor and pushed through editor storage.
|
|
16
|
+
* Enter/exit motion (LC-24) fades through `motionMs`, which is 0 when the
|
|
17
|
+
* animation knob is "none".
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
forwardRef,
|
|
22
|
+
useCallback,
|
|
23
|
+
useEffect,
|
|
24
|
+
useImperativeHandle,
|
|
25
|
+
useRef,
|
|
26
|
+
useState,
|
|
27
|
+
type CSSProperties,
|
|
28
|
+
type ReactNode,
|
|
29
|
+
} from "react";
|
|
30
|
+
import { Extension } from "@tiptap/core";
|
|
31
|
+
import { ReactRenderer } from "@tiptap/react";
|
|
32
|
+
|
|
33
|
+
// ===========================================================================
|
|
34
|
+
// Chrome (resolved theme + knob values, no raw fallbacks)
|
|
35
|
+
// ===========================================================================
|
|
36
|
+
|
|
37
|
+
export interface SuggestionChrome {
|
|
38
|
+
/** Panel surface color (theme background) */
|
|
39
|
+
background: string;
|
|
40
|
+
/** Panel border color */
|
|
41
|
+
borderColor: string;
|
|
42
|
+
/** Row highlight surface (active/hover) */
|
|
43
|
+
activeBackground: string;
|
|
44
|
+
/** Leading icon tile surface */
|
|
45
|
+
iconTileBackground: string;
|
|
46
|
+
/** Primary row text color */
|
|
47
|
+
titleColor: string;
|
|
48
|
+
/** Secondary row text color */
|
|
49
|
+
descriptionColor: string;
|
|
50
|
+
/** Panel corner radius in px */
|
|
51
|
+
radius: number;
|
|
52
|
+
/** Shared floating-panel shadow (Axiom 14/15 light source) */
|
|
53
|
+
shadow: string;
|
|
54
|
+
/** Enter/exit fade duration in ms (0 = animation none) */
|
|
55
|
+
motionMs: number;
|
|
56
|
+
/**
|
|
57
|
+
* Row horizontal padding in px, resolved from the shared LC-16
|
|
58
|
+
* `menuRowFrame` recipe (theme) by the editor host — the DOM popup never
|
|
59
|
+
* invents its own geometry.
|
|
60
|
+
*/
|
|
61
|
+
rowPaddingX: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Chrome used only when the editor has not pushed resolved values yet
|
|
66
|
+
* (first paint edge — a popup cannot open before the host's push effect
|
|
67
|
+
* runs). Colors reference the tamagui `:root` default-theme custom
|
|
68
|
+
* properties rather than literal values, so even this edge stays sourced
|
|
69
|
+
* from the theme system (Axiom 5).
|
|
70
|
+
*/
|
|
71
|
+
export const fallbackSuggestionChrome: SuggestionChrome = {
|
|
72
|
+
background: "var(--background)",
|
|
73
|
+
borderColor: "var(--borderColor)",
|
|
74
|
+
activeBackground: "var(--color4)",
|
|
75
|
+
iconTileBackground: "var(--color3)",
|
|
76
|
+
titleColor: "var(--color12)",
|
|
77
|
+
descriptionColor: "var(--color11)",
|
|
78
|
+
radius: 8,
|
|
79
|
+
shadow: "0px 8px 28px var(--shadow2), 0px 2px 6px var(--shadow1)",
|
|
80
|
+
motionMs: 120,
|
|
81
|
+
rowPaddingX: 12,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
declare module "@tiptap/core" {
|
|
85
|
+
interface Storage {
|
|
86
|
+
suggestionChrome: { value: SuggestionChrome };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Storage-only extension carrying the resolved suggestion chrome. The
|
|
92
|
+
* editor host (TiptapEditor) resolves theme + knob values in React land and
|
|
93
|
+
* pushes them here so the DOM-portaled popups never invent their own colors.
|
|
94
|
+
*/
|
|
95
|
+
export const SuggestionChromeStore = Extension.create({
|
|
96
|
+
name: "suggestionChrome",
|
|
97
|
+
addStorage(): { value: SuggestionChrome } {
|
|
98
|
+
return { value: fallbackSuggestionChrome };
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/** Reads the resolved chrome pushed by the editor host */
|
|
103
|
+
export function getSuggestionChrome(editor: any): SuggestionChrome {
|
|
104
|
+
return editor?.storage?.suggestionChrome?.value ?? fallbackSuggestionChrome;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ===========================================================================
|
|
108
|
+
// Rows
|
|
109
|
+
// ===========================================================================
|
|
110
|
+
|
|
111
|
+
export interface SuggestionRow {
|
|
112
|
+
key: string;
|
|
113
|
+
title: string;
|
|
114
|
+
description?: string;
|
|
115
|
+
/** Leading glyph rendered inside the icon tile */
|
|
116
|
+
icon?: ReactNode;
|
|
117
|
+
/** Avatar image URL (mentions); takes the icon tile slot */
|
|
118
|
+
avatarUrl?: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface SuggestionListProps {
|
|
122
|
+
rows: SuggestionRow[];
|
|
123
|
+
chrome: SuggestionChrome;
|
|
124
|
+
emptyLabel: string;
|
|
125
|
+
onSelect: (index: number) => void;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface SuggestionListRef {
|
|
129
|
+
onKeyDown: (props: { event: KeyboardEvent }) => boolean;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const SuggestionList = forwardRef<SuggestionListRef, SuggestionListProps>(
|
|
133
|
+
({ rows, chrome, emptyLabel, onSelect }, ref) => {
|
|
134
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
135
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
setSelectedIndex(0);
|
|
139
|
+
}, [rows]);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
const el = listRef.current?.children[selectedIndex] as HTMLElement | undefined;
|
|
143
|
+
el?.scrollIntoView({ block: "nearest" });
|
|
144
|
+
}, [selectedIndex]);
|
|
145
|
+
|
|
146
|
+
const selectItem = useCallback(
|
|
147
|
+
(index: number) => {
|
|
148
|
+
if (rows[index]) onSelect(index);
|
|
149
|
+
},
|
|
150
|
+
[rows, onSelect],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
useImperativeHandle(ref, () => ({
|
|
154
|
+
onKeyDown: ({ event }: { event: KeyboardEvent }) => {
|
|
155
|
+
if (rows.length === 0) return false;
|
|
156
|
+
if (event.key === "ArrowUp") {
|
|
157
|
+
setSelectedIndex((i) => (i + rows.length - 1) % rows.length);
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
if (event.key === "ArrowDown") {
|
|
161
|
+
setSelectedIndex((i) => (i + 1) % rows.length);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
if (event.key === "Enter" || event.key === "Tab") {
|
|
165
|
+
selectItem(selectedIndex);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
},
|
|
170
|
+
}));
|
|
171
|
+
|
|
172
|
+
const containerStyle: CSSProperties = {
|
|
173
|
+
background: chrome.background,
|
|
174
|
+
border: `1px solid ${chrome.borderColor}`,
|
|
175
|
+
borderRadius: `${chrome.radius}px`,
|
|
176
|
+
boxShadow: chrome.shadow,
|
|
177
|
+
// SP-EDGE: container owns only its border -- rows own all padding
|
|
178
|
+
padding: 0,
|
|
179
|
+
maxHeight: "320px",
|
|
180
|
+
overflowY: "auto",
|
|
181
|
+
minWidth: "220px",
|
|
182
|
+
maxWidth: "320px",
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
if (rows.length === 0) {
|
|
186
|
+
return (
|
|
187
|
+
<div style={containerStyle} data-suggestion-popup="true">
|
|
188
|
+
<div
|
|
189
|
+
style={{
|
|
190
|
+
padding: `8px ${chrome.rowPaddingX}px`,
|
|
191
|
+
color: chrome.descriptionColor,
|
|
192
|
+
fontSize: "13px",
|
|
193
|
+
}}
|
|
194
|
+
>
|
|
195
|
+
{emptyLabel}
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<div style={containerStyle} ref={listRef} role="listbox" data-suggestion-popup="true">
|
|
203
|
+
{rows.map((row, index) => (
|
|
204
|
+
<button
|
|
205
|
+
key={row.key}
|
|
206
|
+
role="option"
|
|
207
|
+
aria-selected={index === selectedIndex}
|
|
208
|
+
type="button"
|
|
209
|
+
style={{
|
|
210
|
+
// LC-16 shared menu-row geometry (menuRowFrame): horizontal
|
|
211
|
+
// padding resolved from the theme recipe, 8px vertical, 8px
|
|
212
|
+
// in-row gap, full-width flat rows (SP-EDGE)
|
|
213
|
+
display: "flex",
|
|
214
|
+
alignItems: "center",
|
|
215
|
+
gap: "8px",
|
|
216
|
+
padding: `8px ${chrome.rowPaddingX}px`,
|
|
217
|
+
border: "none",
|
|
218
|
+
background: index === selectedIndex ? chrome.activeBackground : "none",
|
|
219
|
+
width: "100%",
|
|
220
|
+
textAlign: "start",
|
|
221
|
+
cursor: "pointer",
|
|
222
|
+
borderRadius: 0,
|
|
223
|
+
fontSize: "13px",
|
|
224
|
+
lineHeight: "1.3",
|
|
225
|
+
fontFamily: "inherit",
|
|
226
|
+
}}
|
|
227
|
+
onClick={() => selectItem(index)}
|
|
228
|
+
onMouseEnter={() => setSelectedIndex(index)}
|
|
229
|
+
>
|
|
230
|
+
{row.avatarUrl ? (
|
|
231
|
+
<img
|
|
232
|
+
src={row.avatarUrl}
|
|
233
|
+
alt=""
|
|
234
|
+
style={{
|
|
235
|
+
width: "24px",
|
|
236
|
+
height: "24px",
|
|
237
|
+
borderRadius: "50%",
|
|
238
|
+
flexShrink: 0,
|
|
239
|
+
objectFit: "cover",
|
|
240
|
+
}}
|
|
241
|
+
/>
|
|
242
|
+
) : row.icon !== undefined && row.icon !== null ? (
|
|
243
|
+
<span
|
|
244
|
+
aria-hidden="true"
|
|
245
|
+
style={{
|
|
246
|
+
width: "28px",
|
|
247
|
+
height: "28px",
|
|
248
|
+
display: "flex",
|
|
249
|
+
alignItems: "center",
|
|
250
|
+
justifyContent: "center",
|
|
251
|
+
borderRadius: "4px",
|
|
252
|
+
background: chrome.iconTileBackground,
|
|
253
|
+
color: chrome.titleColor,
|
|
254
|
+
fontWeight: 700,
|
|
255
|
+
fontSize: "12px",
|
|
256
|
+
flexShrink: 0,
|
|
257
|
+
}}
|
|
258
|
+
>
|
|
259
|
+
{row.icon}
|
|
260
|
+
</span>
|
|
261
|
+
) : null}
|
|
262
|
+
<span style={{ display: "flex", flexDirection: "column", gap: "1px", minWidth: 0 }}>
|
|
263
|
+
<span
|
|
264
|
+
style={{
|
|
265
|
+
fontWeight: 600,
|
|
266
|
+
color: chrome.titleColor,
|
|
267
|
+
whiteSpace: "nowrap",
|
|
268
|
+
overflow: "hidden",
|
|
269
|
+
textOverflow: "ellipsis",
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
{row.title}
|
|
273
|
+
</span>
|
|
274
|
+
{row.description ? (
|
|
275
|
+
<span style={{ fontSize: "11px", color: chrome.descriptionColor }}>
|
|
276
|
+
{row.description}
|
|
277
|
+
</span>
|
|
278
|
+
) : null}
|
|
279
|
+
</span>
|
|
280
|
+
</button>
|
|
281
|
+
))}
|
|
282
|
+
</div>
|
|
283
|
+
);
|
|
284
|
+
},
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
SuggestionList.displayName = "SuggestionList";
|
|
288
|
+
|
|
289
|
+
// ===========================================================================
|
|
290
|
+
// Popup lifecycle (shared tiptap suggestion render())
|
|
291
|
+
// ===========================================================================
|
|
292
|
+
|
|
293
|
+
interface PopupHandle {
|
|
294
|
+
element: HTMLDivElement;
|
|
295
|
+
destroy: (immediate?: boolean) => void;
|
|
296
|
+
position: (clientRect?: (() => DOMRect | null) | null) => void;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function createPopup(editorDom: HTMLElement, motionMs: number): PopupHandle {
|
|
300
|
+
const popup = document.createElement("div");
|
|
301
|
+
popup.style.position = "fixed";
|
|
302
|
+
// above the fullscreen editor frame (zIndex 100000), which the
|
|
303
|
+
// body-portaled popup would otherwise render underneath
|
|
304
|
+
popup.style.zIndex = "100001";
|
|
305
|
+
// Portal lives on document.body, outside the app font scope; inherit the
|
|
306
|
+
// editor's computed font so the menu matches the app
|
|
307
|
+
popup.style.fontFamily = getComputedStyle(editorDom).fontFamily;
|
|
308
|
+
if (motionMs > 0) {
|
|
309
|
+
popup.style.opacity = "0";
|
|
310
|
+
popup.style.transform = "translateY(4px)";
|
|
311
|
+
popup.style.transition = `opacity ${motionMs}ms ease, transform ${motionMs}ms ease`;
|
|
312
|
+
requestAnimationFrame(() => {
|
|
313
|
+
popup.style.opacity = "1";
|
|
314
|
+
popup.style.transform = "translateY(0)";
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
document.body.appendChild(popup);
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
element: popup,
|
|
321
|
+
position: (clientRect) => {
|
|
322
|
+
const rect = clientRect?.();
|
|
323
|
+
if (!rect) return;
|
|
324
|
+
const menuHeight = Math.min(popup.offsetHeight || 320, 320);
|
|
325
|
+
const below = rect.bottom + 4;
|
|
326
|
+
const flip = below + menuHeight > window.innerHeight && rect.top - menuHeight - 4 > 0;
|
|
327
|
+
popup.style.left = `${Math.min(rect.left, Math.max(8, window.innerWidth - popup.offsetWidth - 8))}px`;
|
|
328
|
+
popup.style.top = flip ? `${rect.top - menuHeight - 4}px` : `${below}px`;
|
|
329
|
+
},
|
|
330
|
+
destroy: (immediate = false) => {
|
|
331
|
+
if (immediate || motionMs === 0) {
|
|
332
|
+
popup.remove();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
popup.style.opacity = "0";
|
|
336
|
+
popup.style.transform = "translateY(4px)";
|
|
337
|
+
popup.style.pointerEvents = "none";
|
|
338
|
+
window.setTimeout(() => popup.remove(), motionMs);
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export interface SuggestionRendererOptions<ItemType> {
|
|
344
|
+
/** Maps suggestion items to shared rows */
|
|
345
|
+
toRow: (item: ItemType) => SuggestionRow;
|
|
346
|
+
/** Reads resolved chrome (editor storage) at open time */
|
|
347
|
+
getChrome: (editor: any) => SuggestionChrome;
|
|
348
|
+
/** Copy for the empty state */
|
|
349
|
+
getEmptyLabel: () => string;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Builds the `render()` lifecycle for a tiptap Suggestion configuration,
|
|
354
|
+
* portaling the shared SuggestionList and wiring keyboard navigation,
|
|
355
|
+
* Escape (consumed -- it must not reach outer handlers like fullscreen
|
|
356
|
+
* exit), repositioning, and enter/exit motion.
|
|
357
|
+
*/
|
|
358
|
+
export function createSuggestionRenderer<ItemType>({
|
|
359
|
+
toRow,
|
|
360
|
+
getChrome,
|
|
361
|
+
getEmptyLabel,
|
|
362
|
+
}: SuggestionRendererOptions<ItemType>) {
|
|
363
|
+
return () => {
|
|
364
|
+
let component: ReactRenderer<SuggestionListRef> | null = null;
|
|
365
|
+
let popup: PopupHandle | null = null;
|
|
366
|
+
|
|
367
|
+
const makeProps = (props: any) => ({
|
|
368
|
+
rows: (props.items as ItemType[]).map(toRow),
|
|
369
|
+
chrome: getChrome(props.editor),
|
|
370
|
+
emptyLabel: getEmptyLabel(),
|
|
371
|
+
onSelect: (index: number) => {
|
|
372
|
+
const item = (props.items as ItemType[])[index];
|
|
373
|
+
if (item !== undefined) props.command(item);
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
onStart: (props: any) => {
|
|
379
|
+
component = new ReactRenderer(SuggestionList, {
|
|
380
|
+
props: makeProps(props),
|
|
381
|
+
editor: props.editor,
|
|
382
|
+
});
|
|
383
|
+
popup = createPopup(props.editor.view.dom, getChrome(props.editor).motionMs);
|
|
384
|
+
popup.element.appendChild(component.element);
|
|
385
|
+
popup.position(props.clientRect);
|
|
386
|
+
// reposition once content has laid out (flip needs real height)
|
|
387
|
+
requestAnimationFrame(() => popup?.position(props.clientRect));
|
|
388
|
+
},
|
|
389
|
+
onUpdate: (props: any) => {
|
|
390
|
+
component?.updateProps(makeProps(props));
|
|
391
|
+
popup?.position(props.clientRect);
|
|
392
|
+
},
|
|
393
|
+
onKeyDown: (props: any) => {
|
|
394
|
+
if (props.event.key === "Escape") {
|
|
395
|
+
// consume the Escape entirely: closing the menu must not also
|
|
396
|
+
// trigger outer Escape handlers (e.g. fullscreen exit)
|
|
397
|
+
props.event.stopPropagation();
|
|
398
|
+
popup?.destroy();
|
|
399
|
+
component?.destroy();
|
|
400
|
+
popup = null;
|
|
401
|
+
component = null;
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
return component?.ref?.onKeyDown(props) ?? false;
|
|
405
|
+
},
|
|
406
|
+
onExit: () => {
|
|
407
|
+
popup?.destroy();
|
|
408
|
+
component?.destroy();
|
|
409
|
+
popup = null;
|
|
410
|
+
component = null;
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
}
|