@bendyline/squisq-editor-react 1.5.1 → 1.5.2
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/dist/index.d.ts +1991 -90
- package/dist/index.js +17088 -82
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/DocumentSettingsDialog.d.ts +0 -26
- package/dist/DocumentSettingsDialog.d.ts.map +0 -1
- package/dist/DocumentSettingsDialog.js +0 -115
- package/dist/DocumentSettingsDialog.js.map +0 -1
- package/dist/DropZoneOverlay.d.ts +0 -24
- package/dist/DropZoneOverlay.d.ts.map +0 -1
- package/dist/DropZoneOverlay.js +0 -53
- package/dist/DropZoneOverlay.js.map +0 -1
- package/dist/EditorContext.d.ts +0 -391
- package/dist/EditorContext.d.ts.map +0 -1
- package/dist/EditorContext.js +0 -471
- package/dist/EditorContext.js.map +0 -1
- package/dist/EditorShell.d.ts +0 -328
- package/dist/EditorShell.d.ts.map +0 -1
- package/dist/EditorShell.js +0 -290
- package/dist/EditorShell.js.map +0 -1
- package/dist/EmojiPicker.d.ts +0 -50
- package/dist/EmojiPicker.d.ts.map +0 -1
- package/dist/EmojiPicker.js +0 -182
- package/dist/EmojiPicker.js.map +0 -1
- package/dist/ImageEditor.d.ts +0 -68
- package/dist/ImageEditor.d.ts.map +0 -1
- package/dist/ImageEditor.js +0 -166
- package/dist/ImageEditor.js.map +0 -1
- package/dist/ImageNodeView.d.ts +0 -27
- package/dist/ImageNodeView.d.ts.map +0 -1
- package/dist/ImageNodeView.js +0 -215
- package/dist/ImageNodeView.js.map +0 -1
- package/dist/ImageViewer.d.ts +0 -26
- package/dist/ImageViewer.d.ts.map +0 -1
- package/dist/ImageViewer.js +0 -119
- package/dist/ImageViewer.js.map +0 -1
- package/dist/InlineIcon.d.ts +0 -17
- package/dist/InlineIcon.d.ts.map +0 -1
- package/dist/InlineIcon.js +0 -72
- package/dist/InlineIcon.js.map +0 -1
- package/dist/InlinePreviewGutter.d.ts +0 -52
- package/dist/InlinePreviewGutter.d.ts.map +0 -1
- package/dist/InlinePreviewGutter.js +0 -397
- package/dist/InlinePreviewGutter.js.map +0 -1
- package/dist/LinkDialog.d.ts +0 -43
- package/dist/LinkDialog.d.ts.map +0 -1
- package/dist/LinkDialog.js +0 -102
- package/dist/LinkDialog.js.map +0 -1
- package/dist/MediaBin.d.ts +0 -29
- package/dist/MediaBin.d.ts.map +0 -1
- package/dist/MediaBin.js +0 -166
- package/dist/MediaBin.js.map +0 -1
- package/dist/MentionExtension.d.ts +0 -22
- package/dist/MentionExtension.d.ts.map +0 -1
- package/dist/MentionExtension.js +0 -245
- package/dist/MentionExtension.js.map +0 -1
- package/dist/OutlinePanel.d.ts +0 -17
- package/dist/OutlinePanel.d.ts.map +0 -1
- package/dist/OutlinePanel.js +0 -167
- package/dist/OutlinePanel.js.map +0 -1
- package/dist/PlainHtmlPreview.d.ts +0 -50
- package/dist/PlainHtmlPreview.d.ts.map +0 -1
- package/dist/PlainHtmlPreview.js +0 -155
- package/dist/PlainHtmlPreview.js.map +0 -1
- package/dist/PreviewControls.d.ts +0 -55
- package/dist/PreviewControls.d.ts.map +0 -1
- package/dist/PreviewControls.js +0 -277
- package/dist/PreviewControls.js.map +0 -1
- package/dist/PreviewPanel.d.ts +0 -29
- package/dist/PreviewPanel.d.ts.map +0 -1
- package/dist/PreviewPanel.js +0 -94
- package/dist/PreviewPanel.js.map +0 -1
- package/dist/RawEditor.d.ts +0 -32
- package/dist/RawEditor.d.ts.map +0 -1
- package/dist/RawEditor.js +0 -440
- package/dist/RawEditor.js.map +0 -1
- package/dist/RecorderEntry.d.ts +0 -24
- package/dist/RecorderEntry.d.ts.map +0 -1
- package/dist/RecorderEntry.js +0 -139
- package/dist/RecorderEntry.js.map +0 -1
- package/dist/StatusBar.d.ts +0 -15
- package/dist/StatusBar.d.ts.map +0 -1
- package/dist/StatusBar.js +0 -24
- package/dist/StatusBar.js.map +0 -1
- package/dist/TemplateAnnotation.d.ts +0 -20
- package/dist/TemplateAnnotation.d.ts.map +0 -1
- package/dist/TemplateAnnotation.js +0 -97
- package/dist/TemplateAnnotation.js.map +0 -1
- package/dist/TemplatePicker.d.ts +0 -53
- package/dist/TemplatePicker.d.ts.map +0 -1
- package/dist/TemplatePicker.js +0 -388
- package/dist/TemplatePicker.js.map +0 -1
- package/dist/ThemeCustomizerPanel.d.ts +0 -32
- package/dist/ThemeCustomizerPanel.d.ts.map +0 -1
- package/dist/ThemeCustomizerPanel.js +0 -256
- package/dist/ThemeCustomizerPanel.js.map +0 -1
- package/dist/ThemePicker.d.ts +0 -33
- package/dist/ThemePicker.d.ts.map +0 -1
- package/dist/ThemePicker.js +0 -148
- package/dist/ThemePicker.js.map +0 -1
- package/dist/Toolbar.d.ts +0 -36
- package/dist/Toolbar.d.ts.map +0 -1
- package/dist/Toolbar.js +0 -1001
- package/dist/Toolbar.js.map +0 -1
- package/dist/Tooltip.d.ts +0 -10
- package/dist/Tooltip.d.ts.map +0 -1
- package/dist/Tooltip.js +0 -104
- package/dist/Tooltip.js.map +0 -1
- package/dist/VersionHistoryPanel.d.ts +0 -14
- package/dist/VersionHistoryPanel.d.ts.map +0 -1
- package/dist/VersionHistoryPanel.js +0 -147
- package/dist/VersionHistoryPanel.js.map +0 -1
- package/dist/ViewMenuPanel.d.ts +0 -13
- package/dist/ViewMenuPanel.d.ts.map +0 -1
- package/dist/ViewMenuPanel.js +0 -58
- package/dist/ViewMenuPanel.js.map +0 -1
- package/dist/ViewSwitcher.d.ts +0 -14
- package/dist/ViewSwitcher.d.ts.map +0 -1
- package/dist/ViewSwitcher.js +0 -26
- package/dist/ViewSwitcher.js.map +0 -1
- package/dist/WysiwygEditor.d.ts +0 -39
- package/dist/WysiwygEditor.d.ts.map +0 -1
- package/dist/WysiwygEditor.js +0 -537
- package/dist/WysiwygEditor.js.map +0 -1
- package/dist/__tests__/detectMarkdown.test.d.ts +0 -2
- package/dist/__tests__/detectMarkdown.test.d.ts.map +0 -1
- package/dist/__tests__/detectMarkdown.test.js +0 -55
- package/dist/__tests__/detectMarkdown.test.js.map +0 -1
- package/dist/__tests__/documentSettingsDialog.test.d.ts +0 -2
- package/dist/__tests__/documentSettingsDialog.test.d.ts.map +0 -1
- package/dist/__tests__/documentSettingsDialog.test.js +0 -132
- package/dist/__tests__/documentSettingsDialog.test.js.map +0 -1
- package/dist/__tests__/emojiPicker.test.d.ts +0 -2
- package/dist/__tests__/emojiPicker.test.d.ts.map +0 -1
- package/dist/__tests__/emojiPicker.test.js +0 -111
- package/dist/__tests__/emojiPicker.test.js.map +0 -1
- package/dist/__tests__/fileKind.test.d.ts +0 -2
- package/dist/__tests__/fileKind.test.d.ts.map +0 -1
- package/dist/__tests__/fileKind.test.js +0 -94
- package/dist/__tests__/fileKind.test.js.map +0 -1
- package/dist/__tests__/imageEditAffordance.test.d.ts +0 -2
- package/dist/__tests__/imageEditAffordance.test.d.ts.map +0 -1
- package/dist/__tests__/imageEditAffordance.test.js +0 -188
- package/dist/__tests__/imageEditAffordance.test.js.map +0 -1
- package/dist/__tests__/imageEditorShell.test.d.ts +0 -2
- package/dist/__tests__/imageEditorShell.test.d.ts.map +0 -1
- package/dist/__tests__/imageEditorShell.test.js +0 -52
- package/dist/__tests__/imageEditorShell.test.js.map +0 -1
- package/dist/__tests__/imageEditorState.test.d.ts +0 -3
- package/dist/__tests__/imageEditorState.test.d.ts.map +0 -1
- package/dist/__tests__/imageEditorState.test.js +0 -148
- package/dist/__tests__/imageEditorState.test.js.map +0 -1
- package/dist/__tests__/inlinePreviewGutter.test.d.ts +0 -2
- package/dist/__tests__/inlinePreviewGutter.test.d.ts.map +0 -1
- package/dist/__tests__/inlinePreviewGutter.test.js +0 -51
- package/dist/__tests__/inlinePreviewGutter.test.js.map +0 -1
- package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts +0 -2
- package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts.map +0 -1
- package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js +0 -63
- package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js.map +0 -1
- package/dist/__tests__/jsonEditor.test.d.ts +0 -2
- package/dist/__tests__/jsonEditor.test.d.ts.map +0 -1
- package/dist/__tests__/jsonEditor.test.js +0 -134
- package/dist/__tests__/jsonEditor.test.js.map +0 -1
- package/dist/__tests__/layersPanel.test.d.ts +0 -2
- package/dist/__tests__/layersPanel.test.d.ts.map +0 -1
- package/dist/__tests__/layersPanel.test.js +0 -84
- package/dist/__tests__/layersPanel.test.js.map +0 -1
- package/dist/__tests__/linkDialogDocPicker.test.d.ts +0 -7
- package/dist/__tests__/linkDialogDocPicker.test.d.ts.map +0 -1
- package/dist/__tests__/linkDialogDocPicker.test.js +0 -75
- package/dist/__tests__/linkDialogDocPicker.test.js.map +0 -1
- package/dist/__tests__/mediaAttachmentFlow.test.d.ts +0 -2
- package/dist/__tests__/mediaAttachmentFlow.test.d.ts.map +0 -1
- package/dist/__tests__/mediaAttachmentFlow.test.js +0 -99
- package/dist/__tests__/mediaAttachmentFlow.test.js.map +0 -1
- package/dist/__tests__/outlinePanel.test.d.ts +0 -2
- package/dist/__tests__/outlinePanel.test.d.ts.map +0 -1
- package/dist/__tests__/outlinePanel.test.js +0 -68
- package/dist/__tests__/outlinePanel.test.js.map +0 -1
- package/dist/__tests__/plainHtmlPreview.test.d.ts +0 -2
- package/dist/__tests__/plainHtmlPreview.test.d.ts.map +0 -1
- package/dist/__tests__/plainHtmlPreview.test.js +0 -87
- package/dist/__tests__/plainHtmlPreview.test.js.map +0 -1
- package/dist/__tests__/propertiesPanel.test.d.ts +0 -2
- package/dist/__tests__/propertiesPanel.test.d.ts.map +0 -1
- package/dist/__tests__/propertiesPanel.test.js +0 -64
- package/dist/__tests__/propertiesPanel.test.js.map +0 -1
- package/dist/__tests__/recorderFormats.test.d.ts +0 -2
- package/dist/__tests__/recorderFormats.test.d.ts.map +0 -1
- package/dist/__tests__/recorderFormats.test.js +0 -121
- package/dist/__tests__/recorderFormats.test.js.map +0 -1
- package/dist/__tests__/recorderTimingJson.test.d.ts +0 -2
- package/dist/__tests__/recorderTimingJson.test.d.ts.map +0 -1
- package/dist/__tests__/recorderTimingJson.test.js +0 -37
- package/dist/__tests__/recorderTimingJson.test.js.map +0 -1
- package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts +0 -2
- package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts.map +0 -1
- package/dist/__tests__/templateAnnotationRoundTrip.test.js +0 -31
- package/dist/__tests__/templateAnnotationRoundTrip.test.js.map +0 -1
- package/dist/__tests__/tiptapBridge.test.d.ts +0 -2
- package/dist/__tests__/tiptapBridge.test.d.ts.map +0 -1
- package/dist/__tests__/tiptapBridge.test.js +0 -303
- package/dist/__tests__/tiptapBridge.test.js.map +0 -1
- package/dist/__tests__/tiptapImageRoundTrip.test.d.ts +0 -2
- package/dist/__tests__/tiptapImageRoundTrip.test.d.ts.map +0 -1
- package/dist/__tests__/tiptapImageRoundTrip.test.js +0 -68
- package/dist/__tests__/tiptapImageRoundTrip.test.js.map +0 -1
- package/dist/__tests__/useImageEditor.test.d.ts +0 -2
- package/dist/__tests__/useImageEditor.test.d.ts.map +0 -1
- package/dist/__tests__/useImageEditor.test.js +0 -131
- package/dist/__tests__/useImageEditor.test.js.map +0 -1
- package/dist/__tests__/useMediaRecorder.test.d.ts +0 -2
- package/dist/__tests__/useMediaRecorder.test.d.ts.map +0 -1
- package/dist/__tests__/useMediaRecorder.test.js +0 -153
- package/dist/__tests__/useMediaRecorder.test.js.map +0 -1
- package/dist/__tests__/versionHistory.test.d.ts +0 -2
- package/dist/__tests__/versionHistory.test.d.ts.map +0 -1
- package/dist/__tests__/versionHistory.test.js +0 -124
- package/dist/__tests__/versionHistory.test.js.map +0 -1
- package/dist/blockSlice.d.ts +0 -24
- package/dist/blockSlice.d.ts.map +0 -1
- package/dist/blockSlice.js +0 -63
- package/dist/blockSlice.js.map +0 -1
- package/dist/buildPreviewDoc.d.ts +0 -22
- package/dist/buildPreviewDoc.d.ts.map +0 -1
- package/dist/buildPreviewDoc.js +0 -262
- package/dist/buildPreviewDoc.js.map +0 -1
- package/dist/detectMarkdown.d.ts +0 -20
- package/dist/detectMarkdown.d.ts.map +0 -1
- package/dist/detectMarkdown.js +0 -61
- package/dist/detectMarkdown.js.map +0 -1
- package/dist/emojiData.d.ts +0 -81
- package/dist/emojiData.d.ts.map +0 -1
- package/dist/emojiData.js +0 -1283
- package/dist/emojiData.js.map +0 -1
- package/dist/fileKind.d.ts +0 -34
- package/dist/fileKind.d.ts.map +0 -1
- package/dist/fileKind.js +0 -144
- package/dist/fileKind.js.map +0 -1
- package/dist/hooks/useFileDrop.d.ts +0 -41
- package/dist/hooks/useFileDrop.d.ts.map +0 -1
- package/dist/hooks/useFileDrop.js +0 -205
- package/dist/hooks/useFileDrop.js.map +0 -1
- package/dist/imageEditor/CanvasSurface.d.ts +0 -31
- package/dist/imageEditor/CanvasSurface.d.ts.map +0 -1
- package/dist/imageEditor/CanvasSurface.js +0 -264
- package/dist/imageEditor/CanvasSurface.js.map +0 -1
- package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts +0 -39
- package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts.map +0 -1
- package/dist/imageEditor/ImageVersionHistoryDropdown.js +0 -283
- package/dist/imageEditor/ImageVersionHistoryDropdown.js.map +0 -1
- package/dist/imageEditor/LayersPanel.d.ts +0 -14
- package/dist/imageEditor/LayersPanel.d.ts.map +0 -1
- package/dist/imageEditor/LayersPanel.js +0 -43
- package/dist/imageEditor/LayersPanel.js.map +0 -1
- package/dist/imageEditor/PropertiesPanel.d.ts +0 -14
- package/dist/imageEditor/PropertiesPanel.d.ts.map +0 -1
- package/dist/imageEditor/PropertiesPanel.js +0 -97
- package/dist/imageEditor/PropertiesPanel.js.map +0 -1
- package/dist/imageEditor/Toolbar.d.ts +0 -30
- package/dist/imageEditor/Toolbar.d.ts.map +0 -1
- package/dist/imageEditor/Toolbar.js +0 -108
- package/dist/imageEditor/Toolbar.js.map +0 -1
- package/dist/imageEditor/icons.d.ts +0 -24
- package/dist/imageEditor/icons.d.ts.map +0 -1
- package/dist/imageEditor/icons.js +0 -45
- package/dist/imageEditor/icons.js.map +0 -1
- package/dist/imageEditor/layers/EditorImageLayer.d.ts +0 -16
- package/dist/imageEditor/layers/EditorImageLayer.d.ts.map +0 -1
- package/dist/imageEditor/layers/EditorImageLayer.js +0 -37
- package/dist/imageEditor/layers/EditorImageLayer.js.map +0 -1
- package/dist/imageEditor/layers/EditorShapeLayer.d.ts +0 -15
- package/dist/imageEditor/layers/EditorShapeLayer.d.ts.map +0 -1
- package/dist/imageEditor/layers/EditorShapeLayer.js +0 -20
- package/dist/imageEditor/layers/EditorShapeLayer.js.map +0 -1
- package/dist/imageEditor/layers/EditorTextLayer.d.ts +0 -18
- package/dist/imageEditor/layers/EditorTextLayer.d.ts.map +0 -1
- package/dist/imageEditor/layers/EditorTextLayer.js +0 -13
- package/dist/imageEditor/layers/EditorTextLayer.js.map +0 -1
- package/dist/imageEditor/layers/SelectionHandles.d.ts +0 -17
- package/dist/imageEditor/layers/SelectionHandles.d.ts.map +0 -1
- package/dist/imageEditor/layers/SelectionHandles.js +0 -19
- package/dist/imageEditor/layers/SelectionHandles.js.map +0 -1
- package/dist/imageEditor/state.d.ts +0 -76
- package/dist/imageEditor/state.d.ts.map +0 -1
- package/dist/imageEditor/state.js +0 -87
- package/dist/imageEditor/state.js.map +0 -1
- package/dist/imageEditor/useImageEditor.d.ts +0 -53
- package/dist/imageEditor/useImageEditor.d.ts.map +0 -1
- package/dist/imageEditor/useImageEditor.js +0 -244
- package/dist/imageEditor/useImageEditor.js.map +0 -1
- package/dist/imageEditor/useImageEditorTokens.d.ts +0 -16
- package/dist/imageEditor/useImageEditorTokens.d.ts.map +0 -1
- package/dist/imageEditor/useImageEditorTokens.js +0 -45
- package/dist/imageEditor/useImageEditorTokens.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/jsonEditor/EmbeddedRichTextField.d.ts +0 -15
- package/dist/jsonEditor/EmbeddedRichTextField.d.ts.map +0 -1
- package/dist/jsonEditor/EmbeddedRichTextField.js +0 -74
- package/dist/jsonEditor/EmbeddedRichTextField.js.map +0 -1
- package/dist/jsonEditor/JsonEditor.d.ts +0 -36
- package/dist/jsonEditor/JsonEditor.d.ts.map +0 -1
- package/dist/jsonEditor/JsonEditor.js +0 -15
- package/dist/jsonEditor/JsonEditor.js.map +0 -1
- package/dist/jsonEditor/JsonEditorContext.d.ts +0 -28
- package/dist/jsonEditor/JsonEditorContext.d.ts.map +0 -1
- package/dist/jsonEditor/JsonEditorContext.js +0 -41
- package/dist/jsonEditor/JsonEditorContext.js.map +0 -1
- package/dist/jsonEditor/RenderNode.d.ts +0 -16
- package/dist/jsonEditor/RenderNode.d.ts.map +0 -1
- package/dist/jsonEditor/RenderNode.js +0 -32
- package/dist/jsonEditor/RenderNode.js.map +0 -1
- package/dist/jsonEditor/editors.d.ts +0 -36
- package/dist/jsonEditor/editors.d.ts.map +0 -1
- package/dist/jsonEditor/editors.js +0 -347
- package/dist/jsonEditor/editors.js.map +0 -1
- package/dist/jsonEditor/index.d.ts +0 -3
- package/dist/jsonEditor/index.d.ts.map +0 -1
- package/dist/jsonEditor/index.js +0 -2
- package/dist/jsonEditor/index.js.map +0 -1
- package/dist/jsonEditor/useJsonEditorTokens.d.ts +0 -13
- package/dist/jsonEditor/useJsonEditorTokens.d.ts.map +0 -1
- package/dist/jsonEditor/useJsonEditorTokens.js +0 -38
- package/dist/jsonEditor/useJsonEditorTokens.js.map +0 -1
- package/dist/mediaDragMime.d.ts +0 -17
- package/dist/mediaDragMime.d.ts.map +0 -1
- package/dist/mediaDragMime.js +0 -22
- package/dist/mediaDragMime.js.map +0 -1
- package/dist/recorder/RecorderButton.d.ts +0 -31
- package/dist/recorder/RecorderButton.d.ts.map +0 -1
- package/dist/recorder/RecorderButton.js +0 -24
- package/dist/recorder/RecorderButton.js.map +0 -1
- package/dist/recorder/RecorderModal.d.ts +0 -59
- package/dist/recorder/RecorderModal.d.ts.map +0 -1
- package/dist/recorder/RecorderModal.js +0 -333
- package/dist/recorder/RecorderModal.js.map +0 -1
- package/dist/recorder/RecorderPanel.d.ts +0 -25
- package/dist/recorder/RecorderPanel.d.ts.map +0 -1
- package/dist/recorder/RecorderPanel.js +0 -30
- package/dist/recorder/RecorderPanel.js.map +0 -1
- package/dist/recorder/formats.d.ts +0 -51
- package/dist/recorder/formats.d.ts.map +0 -1
- package/dist/recorder/formats.js +0 -144
- package/dist/recorder/formats.js.map +0 -1
- package/dist/recorder/hooks/useMediaRecorder.d.ts +0 -90
- package/dist/recorder/hooks/useMediaRecorder.d.ts.map +0 -1
- package/dist/recorder/hooks/useMediaRecorder.js +0 -277
- package/dist/recorder/hooks/useMediaRecorder.js.map +0 -1
- package/dist/recorder/hooks/useStreamPreview.d.ts +0 -22
- package/dist/recorder/hooks/useStreamPreview.d.ts.map +0 -1
- package/dist/recorder/hooks/useStreamPreview.js +0 -44
- package/dist/recorder/hooks/useStreamPreview.js.map +0 -1
- package/dist/recorder/sources/cameraStream.d.ts +0 -22
- package/dist/recorder/sources/cameraStream.d.ts.map +0 -1
- package/dist/recorder/sources/cameraStream.js +0 -24
- package/dist/recorder/sources/cameraStream.js.map +0 -1
- package/dist/recorder/sources/micStream.d.ts +0 -15
- package/dist/recorder/sources/micStream.d.ts.map +0 -1
- package/dist/recorder/sources/micStream.js +0 -24
- package/dist/recorder/sources/micStream.js.map +0 -1
- package/dist/recorder/sources/screenStream.d.ts +0 -53
- package/dist/recorder/sources/screenStream.d.ts.map +0 -1
- package/dist/recorder/sources/screenStream.js +0 -114
- package/dist/recorder/sources/screenStream.js.map +0 -1
- package/dist/recorder/timingJson.d.ts +0 -51
- package/dist/recorder/timingJson.d.ts.map +0 -1
- package/dist/recorder/timingJson.js +0 -42
- package/dist/recorder/timingJson.js.map +0 -1
- package/dist/tiptap/TiptapAudio.d.ts +0 -26
- package/dist/tiptap/TiptapAudio.d.ts.map +0 -1
- package/dist/tiptap/TiptapAudio.js +0 -58
- package/dist/tiptap/TiptapAudio.js.map +0 -1
- package/dist/tiptap/TiptapVideo.d.ts +0 -30
- package/dist/tiptap/TiptapVideo.d.ts.map +0 -1
- package/dist/tiptap/TiptapVideo.js +0 -66
- package/dist/tiptap/TiptapVideo.js.map +0 -1
- package/dist/tiptap/useResolvedMediaSrc.d.ts +0 -2
- package/dist/tiptap/useResolvedMediaSrc.d.ts.map +0 -1
- package/dist/tiptap/useResolvedMediaSrc.js +0 -42
- package/dist/tiptap/useResolvedMediaSrc.js.map +0 -1
- package/dist/tiptapBridge.d.ts +0 -24
- package/dist/tiptapBridge.d.ts.map +0 -1
- package/dist/tiptapBridge.js +0 -749
- package/dist/tiptapBridge.js.map +0 -1
- package/dist/useHeadingLayout.d.ts +0 -54
- package/dist/useHeadingLayout.d.ts.map +0 -1
- package/dist/useHeadingLayout.js +0 -260
- package/dist/useHeadingLayout.js.map +0 -1
- package/dist/utils/collectInlineFontAwesomeCss.d.ts +0 -21
- package/dist/utils/collectInlineFontAwesomeCss.d.ts.map +0 -1
- package/dist/utils/collectInlineFontAwesomeCss.js +0 -68
- package/dist/utils/collectInlineFontAwesomeCss.js.map +0 -1
- package/dist/utils/dropUtils.d.ts +0 -55
- package/dist/utils/dropUtils.d.ts.map +0 -1
- package/dist/utils/dropUtils.js +0 -110
- package/dist/utils/dropUtils.js.map +0 -1
- package/dist/utils/normalizeMalformedAssetUrl.d.ts +0 -15
- package/dist/utils/normalizeMalformedAssetUrl.d.ts.map +0 -1
- package/dist/utils/normalizeMalformedAssetUrl.js +0 -27
- package/dist/utils/normalizeMalformedAssetUrl.js.map +0 -1
package/dist/tiptapBridge.js
DELETED
|
@@ -1,749 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tiptap Bridge
|
|
3
|
-
*
|
|
4
|
-
* Conversion utilities between raw markdown source and Tiptap's JSON/HTML
|
|
5
|
-
* content format. Uses a lightweight HTML-based approach: we convert markdown
|
|
6
|
-
* to a simple HTML representation that Tiptap can consume, and parse
|
|
7
|
-
* Tiptap's HTML output back to markdown.
|
|
8
|
-
*
|
|
9
|
-
* This bridge preserves markdown semantics much better than going through
|
|
10
|
-
* Tiptap's native markdown extension, since we control the conversion
|
|
11
|
-
* using squisq's own parser.
|
|
12
|
-
*/
|
|
13
|
-
import { templateLabel } from './TemplatePicker';
|
|
14
|
-
import { resolveIcon } from '@bendyline/squisq/icons';
|
|
15
|
-
// Hoisted regex patterns for inline markdown ↔ HTML conversion
|
|
16
|
-
const RE_BOLD_STAR = /\*\*(.+?)\*\*/g;
|
|
17
|
-
const RE_BOLD_UNDER = /__(.+?)__/g;
|
|
18
|
-
const RE_ITALIC_STAR = /\*(.+?)\*/g;
|
|
19
|
-
const RE_ITALIC_UNDER = /_(.+?)_/g;
|
|
20
|
-
const RE_STRIKETHROUGH = /~~(.+?)~~/g;
|
|
21
|
-
const RE_INLINE_CODE = /`(.+?)`/g;
|
|
22
|
-
const RE_LINK = /\[(.+?)\]\((.+?)\)/g;
|
|
23
|
-
// `*?` on the alt — an empty alt (``) is valid markdown and
|
|
24
|
-
// the most common shape for pasted/uploaded images that don't yet have
|
|
25
|
-
// a human-picked caption. Previously required at least one alt char,
|
|
26
|
-
// which dropped those images on the floor during markdown→HTML.
|
|
27
|
-
const RE_IMAGE = /!\[(.*?)\]\((.+?)\)/g;
|
|
28
|
-
// Mentions: `@[Display](scheme:id)` — scheme-part must start with a letter
|
|
29
|
-
// so plain `$100` or price-style parentheticals don't accidentally match.
|
|
30
|
-
// remark-stringify may round-trip the colon as `\:` — tolerate either.
|
|
31
|
-
const RE_MENTION = /@\[([^\]]+?)\]\(([a-z][a-z0-9+.-]*)\\?:([^)\s]+)\)/gi;
|
|
32
|
-
const RE_MENTION_TAG = /<span\b[^>]*?\bdata-mention\b[^>]*?>(?:<[^>]+>)*([^<]*)<\/span>/gi;
|
|
33
|
-
// Inline FontAwesome icon. Markdown form: `{[github]}` (bare) or
|
|
34
|
-
// `{[fa-solid:user]}` (qualified). HTML form (produced by the
|
|
35
|
-
// `InlineIcon` Tiptap node and consumed back by `htmlToInline`):
|
|
36
|
-
// `<i data-icon="github" data-family="brands" data-name="github"
|
|
37
|
-
// class="fa-brands fa-github" contenteditable="false"></i>`.
|
|
38
|
-
const RE_ICON_MD = /\{\[([a-zA-Z0-9_:-]+)\]\}/g;
|
|
39
|
-
const RE_ICON_TAG = /<i\b[^>]*?\bdata-icon="([^"]*)"[^>]*?><\/i>/gi;
|
|
40
|
-
const RE_STRONG_TAG = /<strong>(.*?)<\/strong>/g;
|
|
41
|
-
const RE_B_TAG = /<b>(.*?)<\/b>/g;
|
|
42
|
-
const RE_EM_TAG = /<em>(.*?)<\/em>/g;
|
|
43
|
-
const RE_I_TAG = /<i>(.*?)<\/i>/g;
|
|
44
|
-
const RE_S_TAG = /<s>(.*?)<\/s>/g;
|
|
45
|
-
const RE_DEL_TAG = /<del>(.*?)<\/del>/g;
|
|
46
|
-
const RE_CODE_TAG = /<code>(.*?)<\/code>/g;
|
|
47
|
-
const RE_A_TAG = /<a[^>]+href="([^"]*)"[^>]*>(.*?)<\/a>/g;
|
|
48
|
-
// Matches any `<img>` tag and captures its `src` + `alt` regardless of
|
|
49
|
-
// attribute order. TipTap's Image extension renders `<img src="..."
|
|
50
|
-
// alt="...">` (src first), while some other producers — including our
|
|
51
|
-
// own `markdownToTiptap` conversion — emit alt-first. The previous
|
|
52
|
-
// regex required alt-before-src and silently dropped every src-first
|
|
53
|
-
// image; `RE_STRIP_TAGS` below would then delete the unmatched tag,
|
|
54
|
-
// so the outgoing markdown had no image reference at all.
|
|
55
|
-
const RE_IMG_TAG = /<img\b([^>]*)>/g;
|
|
56
|
-
const RE_STRIP_TAGS = /<[^>]+>/g;
|
|
57
|
-
/**
|
|
58
|
-
* Convert raw markdown source to Tiptap-consumable HTML content.
|
|
59
|
-
* Uses a simple markdown-to-HTML conversion that maps cleanly to
|
|
60
|
-
* Tiptap's ProseMirror schema.
|
|
61
|
-
*/
|
|
62
|
-
export function markdownToTiptap(markdown) {
|
|
63
|
-
if (!markdown.trim())
|
|
64
|
-
return '<p></p>';
|
|
65
|
-
// Normalize line endings — content from zip archives may use \r\n
|
|
66
|
-
const html = markdown.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
67
|
-
// Process blocks line by line for accurate conversion
|
|
68
|
-
const lines = html.split('\n');
|
|
69
|
-
const outputBlocks = [];
|
|
70
|
-
let inCodeBlock = false;
|
|
71
|
-
let codeBlockLang = '';
|
|
72
|
-
let codeBlockLines = [];
|
|
73
|
-
let inList = false;
|
|
74
|
-
let listItems = [];
|
|
75
|
-
let listType = 'ul';
|
|
76
|
-
let inTable = false;
|
|
77
|
-
let tableLines = [];
|
|
78
|
-
const flushList = () => {
|
|
79
|
-
if (inList && listItems.length > 0) {
|
|
80
|
-
const tag = listType === 'ol' ? 'ol' : 'ul';
|
|
81
|
-
const attr = listType === 'task' ? ' data-type="taskList"' : '';
|
|
82
|
-
outputBlocks.push(`<${tag}${attr}>${listItems.join('')}</${tag}>`);
|
|
83
|
-
listItems = [];
|
|
84
|
-
inList = false;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
const flushTable = () => {
|
|
88
|
-
if (!inTable || tableLines.length === 0) {
|
|
89
|
-
inTable = false;
|
|
90
|
-
tableLines = [];
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
// Validate: need at least 2 lines and second must be a separator
|
|
94
|
-
const separatorCells = tableLines.length >= 2 ? parseTableCells(tableLines[1]) : [];
|
|
95
|
-
const isSeparator = separatorCells.length > 0 && separatorCells.every((cell) => /^:?-+:?$/.test(cell.trim()));
|
|
96
|
-
if (tableLines.length < 2 || !isSeparator) {
|
|
97
|
-
// Not a valid table — render accumulated lines as paragraphs
|
|
98
|
-
for (const tl of tableLines) {
|
|
99
|
-
outputBlocks.push(`<p>${inlineToHtml(tl)}</p>`);
|
|
100
|
-
}
|
|
101
|
-
inTable = false;
|
|
102
|
-
tableLines = [];
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const alignments = parseAlignments(tableLines[1]);
|
|
106
|
-
const headerCells = parseTableCells(tableLines[0]);
|
|
107
|
-
// Build header row
|
|
108
|
-
const thHtml = headerCells
|
|
109
|
-
.map((cell, i) => {
|
|
110
|
-
const align = alignments[i];
|
|
111
|
-
const style = align ? ` style="text-align: ${align}"` : '';
|
|
112
|
-
return `<th${style}>${inlineToHtml(cell)}</th>`;
|
|
113
|
-
})
|
|
114
|
-
.join('');
|
|
115
|
-
// Build body rows
|
|
116
|
-
const bodyHtml = tableLines
|
|
117
|
-
.slice(2)
|
|
118
|
-
.map((rowLine) => {
|
|
119
|
-
const cells = parseTableCells(rowLine);
|
|
120
|
-
const tdHtml = cells
|
|
121
|
-
.map((cell, i) => {
|
|
122
|
-
const align = alignments[i];
|
|
123
|
-
const style = align ? ` style="text-align: ${align}"` : '';
|
|
124
|
-
return `<td${style}>${inlineToHtml(cell)}</td>`;
|
|
125
|
-
})
|
|
126
|
-
.join('');
|
|
127
|
-
return `<tr>${tdHtml}</tr>`;
|
|
128
|
-
})
|
|
129
|
-
.join('');
|
|
130
|
-
outputBlocks.push(`<table><thead><tr>${thHtml}</tr></thead><tbody>${bodyHtml}</tbody></table>`);
|
|
131
|
-
inTable = false;
|
|
132
|
-
tableLines = [];
|
|
133
|
-
};
|
|
134
|
-
for (let i = 0; i < lines.length; i++) {
|
|
135
|
-
const line = lines[i];
|
|
136
|
-
// Code fence handling
|
|
137
|
-
if (line.startsWith('```')) {
|
|
138
|
-
if (!inCodeBlock) {
|
|
139
|
-
flushList();
|
|
140
|
-
inCodeBlock = true;
|
|
141
|
-
codeBlockLang = line.slice(3).trim();
|
|
142
|
-
codeBlockLines = [];
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
const langAttr = codeBlockLang ? ` class="language-${escapeHtml(codeBlockLang)}"` : '';
|
|
147
|
-
outputBlocks.push(`<pre><code${langAttr}>${escapeHtml(codeBlockLines.join('\n'))}</code></pre>`);
|
|
148
|
-
inCodeBlock = false;
|
|
149
|
-
codeBlockLang = '';
|
|
150
|
-
codeBlockLines = [];
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (inCodeBlock) {
|
|
155
|
-
codeBlockLines.push(line);
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
// If in table and current line is not a table row, flush
|
|
159
|
-
if (inTable && !/^\|.*\|$/.test(line.trim())) {
|
|
160
|
-
flushTable();
|
|
161
|
-
}
|
|
162
|
-
// Blank line flushes list
|
|
163
|
-
if (line.trim() === '') {
|
|
164
|
-
flushList();
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
// Headings
|
|
168
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
169
|
-
if (headingMatch) {
|
|
170
|
-
flushList();
|
|
171
|
-
const level = headingMatch[1].length;
|
|
172
|
-
let text = headingMatch[2];
|
|
173
|
-
let attrs = '';
|
|
174
|
-
// Extract {[template key=value …]} annotation. Trailing `[\s\]\}]*`
|
|
175
|
-
// tolerates accidental doubled `]}` that users type while learning
|
|
176
|
-
// the syntax — must stay in sync with TEMPLATE_ANNOTATION_RE in
|
|
177
|
-
// packages/core/src/markdown/convert.ts.
|
|
178
|
-
const annotMatch = text.match(/\s*\{\[([^\]]+)\]\}[\s\]}]*$/);
|
|
179
|
-
if (annotMatch) {
|
|
180
|
-
text = text.slice(0, annotMatch.index).trimEnd();
|
|
181
|
-
const tokens = annotMatch[1].trim().split(/\s+/);
|
|
182
|
-
attrs = ` data-template="${escapeHtml(tokens[0])}"`;
|
|
183
|
-
const params = tokens.slice(1).filter((t) => t.includes('='));
|
|
184
|
-
if (params.length > 0) {
|
|
185
|
-
attrs += ` data-template-params="${escapeHtml(params.join(' '))}"`;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
outputBlocks.push(`<h${level}${attrs}>${inlineToHtml(text)}</h${level}>`);
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
// Thematic break
|
|
192
|
-
if (/^(---|\*\*\*|___)(\s*)$/.test(line.trim())) {
|
|
193
|
-
flushList();
|
|
194
|
-
outputBlocks.push('<hr>');
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
// Blockquote
|
|
198
|
-
if (line.startsWith('> ')) {
|
|
199
|
-
flushList();
|
|
200
|
-
outputBlocks.push(`<blockquote><p>${inlineToHtml(line.slice(2))}</p></blockquote>`);
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
// Task list item
|
|
204
|
-
const taskMatch = line.match(/^[-*+]\s+\[([xX ])\]\s+(.+)$/);
|
|
205
|
-
if (taskMatch) {
|
|
206
|
-
if (!inList || listType !== 'task') {
|
|
207
|
-
flushList();
|
|
208
|
-
inList = true;
|
|
209
|
-
listType = 'task';
|
|
210
|
-
}
|
|
211
|
-
const checked = taskMatch[1].toLowerCase() === 'x' ? ' data-checked="true"' : '';
|
|
212
|
-
listItems.push(`<li data-type="taskItem"${checked}><label><input type="checkbox"${checked ? ' checked' : ''}>${inlineToHtml(taskMatch[2])}</label></li>`);
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
// Unordered list item
|
|
216
|
-
const ulMatch = line.match(/^[-*+]\s+(.+)$/);
|
|
217
|
-
if (ulMatch) {
|
|
218
|
-
if (!inList || listType !== 'ul') {
|
|
219
|
-
flushList();
|
|
220
|
-
inList = true;
|
|
221
|
-
listType = 'ul';
|
|
222
|
-
}
|
|
223
|
-
listItems.push(`<li><p>${inlineToHtml(ulMatch[1])}</p></li>`);
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
// Ordered list item
|
|
227
|
-
const olMatch = line.match(/^\d+\.\s+(.+)$/);
|
|
228
|
-
if (olMatch) {
|
|
229
|
-
if (!inList || listType !== 'ol') {
|
|
230
|
-
flushList();
|
|
231
|
-
inList = true;
|
|
232
|
-
listType = 'ol';
|
|
233
|
-
}
|
|
234
|
-
listItems.push(`<li><p>${inlineToHtml(olMatch[1])}</p></li>`);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
// Table row
|
|
238
|
-
if (/^\|.*\|$/.test(line.trim())) {
|
|
239
|
-
if (!inTable) {
|
|
240
|
-
flushList();
|
|
241
|
-
inTable = true;
|
|
242
|
-
tableLines = [];
|
|
243
|
-
}
|
|
244
|
-
tableLines.push(line);
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
// Standalone image — emit as a top-level block `<img>` instead of
|
|
248
|
-
// wrapping in `<p>`. The Tiptap Image extension is configured with
|
|
249
|
-
// `inline: false`, so `<p><img></p>` parses to an empty paragraph
|
|
250
|
-
// (the block image can't live inside the paragraph). That bug
|
|
251
|
-
// manifested as a broken-image glyph after a markdown → WYSIWYG
|
|
252
|
-
// round-trip for any dropped/pasted image.
|
|
253
|
-
const standaloneImageMatch = line.trim().match(/^!\[(.*?)\]\((.+?)\)$/);
|
|
254
|
-
if (standaloneImageMatch) {
|
|
255
|
-
flushList();
|
|
256
|
-
const alt = escapeHtml(standaloneImageMatch[1] ?? '');
|
|
257
|
-
const src = escapeHtml(standaloneImageMatch[2] ?? '');
|
|
258
|
-
outputBlocks.push(`<img alt="${alt}" src="${src}">`);
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
// Standalone raw HTML `<img>` line — emitted by `tiptapToMarkdown`
|
|
262
|
-
// when the user has resized an image (width/height attrs are
|
|
263
|
-
// serialized as HTML rather than markdown shorthand so the
|
|
264
|
-
// dimensions survive round-trip). Pass the tag through unchanged
|
|
265
|
-
// so Tiptap's Image extension parses width/height attributes.
|
|
266
|
-
const trimmed = line.trim();
|
|
267
|
-
if (/^<img\b[^>]*>$/i.test(trimmed)) {
|
|
268
|
-
flushList();
|
|
269
|
-
outputBlocks.push(trimmed);
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
// Standalone `<video>` / `<audio>` line — emitted by the recorder
|
|
273
|
-
// (RecorderEntry) when it saves a clip, and by `tiptapToMarkdown`
|
|
274
|
-
// when the WYSIWYG editor's TiptapVideo/TiptapAudio nodes serialize
|
|
275
|
-
// back to markdown. Pass through unchanged so the editor's parseHTML
|
|
276
|
-
// picks up the tag attributes (`src`, `controls`, …).
|
|
277
|
-
if (/^<(?:video|audio)\b[^>]*>(?:[\s\S]*?<\/(?:video|audio)>)?$/i.test(trimmed)) {
|
|
278
|
-
flushList();
|
|
279
|
-
outputBlocks.push(trimmed);
|
|
280
|
-
continue;
|
|
281
|
-
}
|
|
282
|
-
// Regular paragraph
|
|
283
|
-
flushList();
|
|
284
|
-
outputBlocks.push(`<p>${inlineToHtml(line)}</p>`);
|
|
285
|
-
}
|
|
286
|
-
// Close any remaining open blocks
|
|
287
|
-
if (inCodeBlock) {
|
|
288
|
-
const langAttr = codeBlockLang ? ` class="language-${escapeHtml(codeBlockLang)}"` : '';
|
|
289
|
-
outputBlocks.push(`<pre><code${langAttr}>${escapeHtml(codeBlockLines.join('\n'))}</code></pre>`);
|
|
290
|
-
}
|
|
291
|
-
flushList();
|
|
292
|
-
flushTable();
|
|
293
|
-
return outputBlocks.join('') || '<p></p>';
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Convert Tiptap HTML output back to markdown source.
|
|
297
|
-
* Extracts semantic structure from HTML and produces clean markdown.
|
|
298
|
-
*/
|
|
299
|
-
export function tiptapToMarkdown(html) {
|
|
300
|
-
if (!html || html === '<p></p>')
|
|
301
|
-
return '';
|
|
302
|
-
const lines = [];
|
|
303
|
-
// Simple regex-based HTML to markdown conversion
|
|
304
|
-
// This works because Tiptap produces clean, predictable HTML
|
|
305
|
-
let remaining = html;
|
|
306
|
-
while (remaining.length > 0) {
|
|
307
|
-
// Headings
|
|
308
|
-
const headingMatch = remaining.match(/^<h([1-6])([^>]*)>(.*?)<\/h\1>/s);
|
|
309
|
-
if (headingMatch) {
|
|
310
|
-
const level = parseInt(headingMatch[1], 10);
|
|
311
|
-
const attrs = headingMatch[2];
|
|
312
|
-
let text = htmlToInline(headingMatch[3]);
|
|
313
|
-
// Re-inject template annotation from data attributes
|
|
314
|
-
const tmplMatch = attrs.match(/data-template="([^"]+)"/);
|
|
315
|
-
if (tmplMatch) {
|
|
316
|
-
let annotation = tmplMatch[1];
|
|
317
|
-
// Defensive: an earlier broken build briefly rendered the
|
|
318
|
-
// template label as a real text node inside the badge, which
|
|
319
|
-
// bled the label into the heading's textContent. Strip a
|
|
320
|
-
// trailing copy of the template's label so existing documents
|
|
321
|
-
// self-heal on save.
|
|
322
|
-
const label = templateLabel(annotation);
|
|
323
|
-
if (label && text.endsWith(label)) {
|
|
324
|
-
text = text.slice(0, -label.length).trimEnd();
|
|
325
|
-
}
|
|
326
|
-
const paramsMatch = attrs.match(/data-template-params="([^"]+)"/);
|
|
327
|
-
if (paramsMatch) {
|
|
328
|
-
annotation += ' ' + unescapeHtml(paramsMatch[1]);
|
|
329
|
-
}
|
|
330
|
-
text += ` {[${annotation}]}`;
|
|
331
|
-
}
|
|
332
|
-
lines.push('#'.repeat(level) + ' ' + text);
|
|
333
|
-
lines.push('');
|
|
334
|
-
remaining = remaining.slice(headingMatch[0].length);
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
// Code blocks
|
|
338
|
-
const codeMatch = remaining.match(/^<pre><code(?:\s+class="language-([^"]*)")?>(.*?)<\/code><\/pre>/s);
|
|
339
|
-
if (codeMatch) {
|
|
340
|
-
const lang = codeMatch[1] || '';
|
|
341
|
-
const code = unescapeHtml(codeMatch[2]);
|
|
342
|
-
lines.push('```' + lang);
|
|
343
|
-
lines.push(code);
|
|
344
|
-
lines.push('```');
|
|
345
|
-
lines.push('');
|
|
346
|
-
remaining = remaining.slice(codeMatch[0].length);
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
// Blockquote
|
|
350
|
-
const bqMatch = remaining.match(/^<blockquote>(.*?)<\/blockquote>/s);
|
|
351
|
-
if (bqMatch) {
|
|
352
|
-
const inner = htmlToInline(bqMatch[1].replace(/<\/?p>/g, ''));
|
|
353
|
-
lines.push('> ' + inner);
|
|
354
|
-
lines.push('');
|
|
355
|
-
remaining = remaining.slice(bqMatch[0].length);
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
// Horizontal rule
|
|
359
|
-
if (remaining.startsWith('<hr>') ||
|
|
360
|
-
remaining.startsWith('<hr/>') ||
|
|
361
|
-
remaining.startsWith('<hr />')) {
|
|
362
|
-
const hrMatch = remaining.match(/^<hr\s*\/?>/);
|
|
363
|
-
lines.push('---');
|
|
364
|
-
lines.push('');
|
|
365
|
-
remaining = remaining.slice(hrMatch[0].length);
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
// Table (with optional Tiptap tableWrapper div; table tag may have style attrs)
|
|
369
|
-
const tableMatch = remaining.match(/^<div[^>]*class="[^"]*tableWrapper[^"]*"[^>]*><table[^>]*>(.*?)<\/table>\s*<\/div>/s) || remaining.match(/^<table[^>]*>(.*?)<\/table>/s);
|
|
370
|
-
if (tableMatch) {
|
|
371
|
-
const tableContent = tableMatch[1];
|
|
372
|
-
// Extract all rows with their cells
|
|
373
|
-
const rows = [];
|
|
374
|
-
const rowRegex = /<tr[^>]*>(.*?)<\/tr>/gs;
|
|
375
|
-
let rowExec;
|
|
376
|
-
while ((rowExec = rowRegex.exec(tableContent)) !== null) {
|
|
377
|
-
const rowHtml = rowExec[1];
|
|
378
|
-
const cells = [];
|
|
379
|
-
const cellRegex = /<(th|td)([^>]*)>(.*?)<\/\1>/gs;
|
|
380
|
-
let cellExec;
|
|
381
|
-
while ((cellExec = cellRegex.exec(rowHtml)) !== null) {
|
|
382
|
-
const tag = cellExec[1];
|
|
383
|
-
const attrs = cellExec[2];
|
|
384
|
-
const content = htmlToInline(cellExec[3].replace(/<\/?p>/g, ''));
|
|
385
|
-
const alignExec = attrs.match(/text-align:\s*(left|center|right)/);
|
|
386
|
-
cells.push({
|
|
387
|
-
content,
|
|
388
|
-
align: alignExec ? alignExec[1] : null,
|
|
389
|
-
isHeader: tag === 'th',
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
if (cells.length > 0) {
|
|
393
|
-
rows.push(cells);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (rows.length > 0) {
|
|
397
|
-
// Header row = first row with th cells, or just the first row
|
|
398
|
-
const headerIdx = rows.findIndex((r) => r.some((c) => c.isHeader));
|
|
399
|
-
const hIdx = headerIdx >= 0 ? headerIdx : 0;
|
|
400
|
-
const headerRow = rows[hIdx];
|
|
401
|
-
const dataRows = rows.filter((_, i) => i !== hIdx);
|
|
402
|
-
const aligns = headerRow.map((c) => c.align);
|
|
403
|
-
lines.push('| ' + headerRow.map((c) => c.content || ' ').join(' | ') + ' |');
|
|
404
|
-
lines.push('| ' +
|
|
405
|
-
aligns
|
|
406
|
-
.map((a) => {
|
|
407
|
-
if (a === 'center')
|
|
408
|
-
return ':---:';
|
|
409
|
-
if (a === 'right')
|
|
410
|
-
return '---:';
|
|
411
|
-
return '---';
|
|
412
|
-
})
|
|
413
|
-
.join(' | ') +
|
|
414
|
-
' |');
|
|
415
|
-
for (const row of dataRows) {
|
|
416
|
-
lines.push('| ' + row.map((c) => c.content || ' ').join(' | ') + ' |');
|
|
417
|
-
}
|
|
418
|
-
lines.push('');
|
|
419
|
-
}
|
|
420
|
-
remaining = remaining.slice(tableMatch[0].length);
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
// Task list
|
|
424
|
-
const taskListMatch = remaining.match(/^<ul[^>]*data-type="taskList"[^>]*>(.*?)<\/ul>/s);
|
|
425
|
-
if (taskListMatch) {
|
|
426
|
-
const items = taskListMatch[1].matchAll(/<li[^>]*data-type="taskItem"[^>]*(data-checked="true")?[^>]*>.*?<\/li>/gs);
|
|
427
|
-
for (const item of items) {
|
|
428
|
-
const checked = item[0].includes('data-checked="true"') || item[0].includes('checked');
|
|
429
|
-
const textMatch = item[0].match(/<label>.*?<\/label>|<p>(.*?)<\/p>/s);
|
|
430
|
-
const text = textMatch ? htmlToInline(textMatch[0].replace(/<[^>]+>/g, '')) : '';
|
|
431
|
-
lines.push(`- [${checked ? 'x' : ' '}] ${text}`);
|
|
432
|
-
}
|
|
433
|
-
lines.push('');
|
|
434
|
-
remaining = remaining.slice(taskListMatch[0].length);
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
// Unordered list
|
|
438
|
-
const ulMatch = remaining.match(/^<ul>(.*?)<\/ul>/s);
|
|
439
|
-
if (ulMatch) {
|
|
440
|
-
const items = ulMatch[1].matchAll(/<li>(.*?)<\/li>/gs);
|
|
441
|
-
for (const item of items) {
|
|
442
|
-
lines.push(...renderListItem('- ', item[1]));
|
|
443
|
-
}
|
|
444
|
-
lines.push('');
|
|
445
|
-
remaining = remaining.slice(ulMatch[0].length);
|
|
446
|
-
continue;
|
|
447
|
-
}
|
|
448
|
-
// Ordered list
|
|
449
|
-
const olMatch = remaining.match(/^<ol[^>]*>(.*?)<\/ol>/s);
|
|
450
|
-
if (olMatch) {
|
|
451
|
-
const items = [...olMatch[1].matchAll(/<li>(.*?)<\/li>/gs)];
|
|
452
|
-
items.forEach((item, idx) => {
|
|
453
|
-
lines.push(...renderListItem(`${idx + 1}. `, item[1]));
|
|
454
|
-
});
|
|
455
|
-
lines.push('');
|
|
456
|
-
remaining = remaining.slice(olMatch[0].length);
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
// Paragraph
|
|
460
|
-
const pMatch = remaining.match(/^<p>(.*?)<\/p>/s);
|
|
461
|
-
if (pMatch) {
|
|
462
|
-
const text = htmlToInline(pMatch[1]);
|
|
463
|
-
if (text.trim()) {
|
|
464
|
-
lines.push(text);
|
|
465
|
-
lines.push('');
|
|
466
|
-
}
|
|
467
|
-
remaining = remaining.slice(pMatch[0].length);
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
// Block-level image. TipTap's Image extension with `inline: false`
|
|
471
|
-
// emits `<img src alt>` as a bare top-level element (no wrapping
|
|
472
|
-
// `<p>`). Without this handler the skip-unknown-tags catch-all
|
|
473
|
-
// below silently drops the image from the outgoing markdown —
|
|
474
|
-
// the bug that made the chat composer ship image-less messages
|
|
475
|
-
// even though the editor showed the picture. Handled here,
|
|
476
|
-
// before the inline walker ever sees it.
|
|
477
|
-
const imgMatch = remaining.match(/^<img\b([^>]*)>/);
|
|
478
|
-
if (imgMatch) {
|
|
479
|
-
const attrs = imgMatch[1] ?? '';
|
|
480
|
-
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1];
|
|
481
|
-
if (src) {
|
|
482
|
-
const alt = /\balt="([^"]*)"/i.exec(attrs)?.[1] ?? '';
|
|
483
|
-
lines.push(serializeImage(src, alt, attrs));
|
|
484
|
-
lines.push('');
|
|
485
|
-
}
|
|
486
|
-
remaining = remaining.slice(imgMatch[0].length);
|
|
487
|
-
continue;
|
|
488
|
-
}
|
|
489
|
-
// Block-level `<video>` / `<audio>` — emitted by our TiptapVideo /
|
|
490
|
-
// TiptapAudio atom nodes (block group). Serialize the whole tag
|
|
491
|
-
// (opening + closing) back to markdown unchanged; CommonMark allows
|
|
492
|
-
// inline HTML, and our renderer plus the InlinePreviewGutter both
|
|
493
|
-
// know how to parse the htmlElement back out.
|
|
494
|
-
const mediaMatch = remaining.match(/^<(video|audio)\b([^>]*)>(?:[\s\S]*?<\/\1>)?/);
|
|
495
|
-
if (mediaMatch) {
|
|
496
|
-
const tag = mediaMatch[1] === 'video' ? 'video' : 'audio';
|
|
497
|
-
lines.push(serializeMediaTag(tag, mediaMatch[2] ?? ''));
|
|
498
|
-
lines.push('');
|
|
499
|
-
remaining = remaining.slice(mediaMatch[0].length);
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
// Skip unknown tags or whitespace
|
|
503
|
-
const skipMatch = remaining.match(/^(<[^>]+>|\s+)/);
|
|
504
|
-
if (skipMatch) {
|
|
505
|
-
remaining = remaining.slice(skipMatch[0].length);
|
|
506
|
-
continue;
|
|
507
|
-
}
|
|
508
|
-
// Plain text (shouldn't happen in well-formed Tiptap output)
|
|
509
|
-
const textMatch = remaining.match(/^([^<]+)/);
|
|
510
|
-
if (textMatch) {
|
|
511
|
-
lines.push(unescapeHtml(textMatch[1]));
|
|
512
|
-
remaining = remaining.slice(textMatch[0].length);
|
|
513
|
-
continue;
|
|
514
|
-
}
|
|
515
|
-
// Safety: skip one character to avoid infinite loop
|
|
516
|
-
remaining = remaining.slice(1);
|
|
517
|
-
}
|
|
518
|
-
// Clean up trailing blank lines
|
|
519
|
-
return (lines
|
|
520
|
-
.join('\n')
|
|
521
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
522
|
-
.trim() + '\n');
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Render a list item's HTML content as one or more markdown lines.
|
|
526
|
-
* Handles `<p>` paragraph breaks (blank line) and `<br>` hard breaks
|
|
527
|
-
* (two trailing spaces). Continuation lines are indented to keep them
|
|
528
|
-
* inside the list item.
|
|
529
|
-
*/
|
|
530
|
-
function renderListItem(prefix, html) {
|
|
531
|
-
const indent = ' '.repeat(prefix.length);
|
|
532
|
-
// Split on </p><p> to detect paragraph breaks within the item
|
|
533
|
-
const paragraphs = html
|
|
534
|
-
.split(/<\/p>\s*<p[^>]*>/i)
|
|
535
|
-
.map((p) => p.replace(/^<p[^>]*>/i, '').replace(/<\/p>\s*$/i, ''));
|
|
536
|
-
const result = [];
|
|
537
|
-
paragraphs.forEach((paragraph, pIdx) => {
|
|
538
|
-
const inline = htmlToInline(paragraph).trim();
|
|
539
|
-
if (!inline)
|
|
540
|
-
return;
|
|
541
|
-
// Each <br> already became " \n" in htmlToInline; split on it now.
|
|
542
|
-
const subLines = inline.split('\n');
|
|
543
|
-
subLines.forEach((sub, sIdx) => {
|
|
544
|
-
if (pIdx === 0 && sIdx === 0) {
|
|
545
|
-
result.push(prefix + sub);
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
// Blank line separator between paragraphs (sIdx === 0 means new paragraph)
|
|
549
|
-
if (sIdx === 0)
|
|
550
|
-
result.push('');
|
|
551
|
-
result.push(indent + sub);
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
});
|
|
555
|
-
return result.length > 0 ? result : [prefix];
|
|
556
|
-
}
|
|
557
|
-
// ─── Table helpers ───────────────────────────────────────
|
|
558
|
-
/** Split a GFM table row into trimmed cell strings (strips outer pipes). */
|
|
559
|
-
function parseTableCells(line) {
|
|
560
|
-
let inner = line.trim();
|
|
561
|
-
if (inner.startsWith('|'))
|
|
562
|
-
inner = inner.slice(1);
|
|
563
|
-
if (inner.endsWith('|'))
|
|
564
|
-
inner = inner.slice(0, -1);
|
|
565
|
-
return inner.split('|').map((cell) => cell.trim());
|
|
566
|
-
}
|
|
567
|
-
/** Parse a GFM separator line into column alignments. */
|
|
568
|
-
function parseAlignments(separatorLine) {
|
|
569
|
-
return parseTableCells(separatorLine).map((cell) => {
|
|
570
|
-
const s = cell.replace(/\s/g, '');
|
|
571
|
-
if (s.startsWith(':') && s.endsWith(':'))
|
|
572
|
-
return 'center';
|
|
573
|
-
if (s.endsWith(':'))
|
|
574
|
-
return 'right';
|
|
575
|
-
if (s.startsWith(':'))
|
|
576
|
-
return 'left';
|
|
577
|
-
return null;
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
// ─── Helpers ─────────────────────────────────────────────
|
|
581
|
-
/**
|
|
582
|
-
* Serialize a parsed `<img>` tag back to markdown. When the tag carries
|
|
583
|
-
* an explicit `width` and/or `height` we emit a raw HTML `<img>` (the
|
|
584
|
-
* markdown shorthand `` has no syntax for dimensions);
|
|
585
|
-
* otherwise the friendlier shorthand is used. Markdown allows inline
|
|
586
|
-
* HTML, so the HTML form parses and renders identically in any
|
|
587
|
-
* CommonMark/GFM viewer.
|
|
588
|
-
*/
|
|
589
|
-
/**
|
|
590
|
-
* Serialize a `<video>` or `<audio>` tag (from the Tiptap atom node's
|
|
591
|
-
* `renderHTML`) back to markdown. We re-emit only the attributes the
|
|
592
|
-
* recorder + the renderer care about, in a stable order, so the
|
|
593
|
-
* round-tripped markdown stays deterministic regardless of how Tiptap
|
|
594
|
-
* decided to order them on its output.
|
|
595
|
-
*/
|
|
596
|
-
function serializeMediaTag(tag, attrs) {
|
|
597
|
-
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1] ?? '';
|
|
598
|
-
const controls = /\bcontrols\b/i.test(attrs);
|
|
599
|
-
const width = /\bwidth="([^"]*)"/i.exec(attrs)?.[1];
|
|
600
|
-
const height = /\bheight="([^"]*)"/i.exec(attrs)?.[1];
|
|
601
|
-
const poster = tag === 'video' ? /\bposter="([^"]*)"/i.exec(attrs)?.[1] : undefined;
|
|
602
|
-
const parts = [`<${tag} src="${src}"`];
|
|
603
|
-
if (controls)
|
|
604
|
-
parts.push(' controls');
|
|
605
|
-
if (width)
|
|
606
|
-
parts.push(` width="${width}"`);
|
|
607
|
-
if (height)
|
|
608
|
-
parts.push(` height="${height}"`);
|
|
609
|
-
if (poster)
|
|
610
|
-
parts.push(` poster="${poster}"`);
|
|
611
|
-
parts.push(`></${tag}>`);
|
|
612
|
-
return parts.join('');
|
|
613
|
-
}
|
|
614
|
-
function serializeImage(src, alt, attrs) {
|
|
615
|
-
const width = /\bwidth="([^"]*)"/i.exec(attrs)?.[1];
|
|
616
|
-
const height = /\bheight="([^"]*)"/i.exec(attrs)?.[1];
|
|
617
|
-
const title = /\btitle="([^"]*)"/i.exec(attrs)?.[1];
|
|
618
|
-
if (!width && !height) {
|
|
619
|
-
return ``;
|
|
620
|
-
}
|
|
621
|
-
const parts = [`<img alt="${alt}" src="${src}"`];
|
|
622
|
-
if (width)
|
|
623
|
-
parts.push(` width="${width}"`);
|
|
624
|
-
if (height)
|
|
625
|
-
parts.push(` height="${height}"`);
|
|
626
|
-
if (title)
|
|
627
|
-
parts.push(` title="${title}"`);
|
|
628
|
-
parts.push('>');
|
|
629
|
-
return parts.join('');
|
|
630
|
-
}
|
|
631
|
-
function escapeHtml(text) {
|
|
632
|
-
return text
|
|
633
|
-
.replace(/&/g, '&')
|
|
634
|
-
.replace(/</g, '<')
|
|
635
|
-
.replace(/>/g, '>')
|
|
636
|
-
.replace(/"/g, '"');
|
|
637
|
-
}
|
|
638
|
-
function unescapeHtml(text) {
|
|
639
|
-
return text
|
|
640
|
-
.replace(/</g, '<')
|
|
641
|
-
.replace(/>/g, '>')
|
|
642
|
-
.replace(/"/g, '"')
|
|
643
|
-
.replace(/&/g, '&');
|
|
644
|
-
}
|
|
645
|
-
/** Convert inline markdown to HTML for Tiptap consumption */
|
|
646
|
-
function inlineToHtml(text) {
|
|
647
|
-
// Extract images/mentions/links to opaque placeholders BEFORE running
|
|
648
|
-
// any inline-formatting regexes. Otherwise `_` characters inside a URL
|
|
649
|
-
// (e.g. `mikehome_files/IMG_6829.JPEG`) get turned into `<em>` tags by
|
|
650
|
-
// the underscore-italic rule, mangling the src so the image renders
|
|
651
|
-
// broken after a markdown ↔ WYSIWYG round-trip.
|
|
652
|
-
const placeholders = [];
|
|
653
|
-
const stash = (html) => {
|
|
654
|
-
const token = `\u0000PH${placeholders.length}\u0000`;
|
|
655
|
-
placeholders.push(html);
|
|
656
|
-
return token;
|
|
657
|
-
};
|
|
658
|
-
// We run extraction on the RAW text (before escapeHtml) so the
|
|
659
|
-
// captured groups are the literal markdown contents; then we
|
|
660
|
-
// selectively escape the parts of each placeholder that need it.
|
|
661
|
-
// Images first:  — must be before links so the `!` prefix is consumed
|
|
662
|
-
let staged = text.replace(RE_IMAGE, (_m, alt, src) => stash(`<img alt="${escapeHtml(alt)}" src="${escapeHtml(src)}">`));
|
|
663
|
-
// Mentions: @[Display](scheme:id) — must run before links so the
|
|
664
|
-
// bracket+paren isn't consumed as a regular link.
|
|
665
|
-
staged = staged.replace(RE_MENTION, (_m, label, kind, id) => stash(`<span data-mention="true" data-kind="${escapeHtml(kind)}" data-id="${escapeHtml(id)}" data-label="${escapeHtml(label)}" class="mention">@${escapeHtml(label)}</span>`));
|
|
666
|
-
// FontAwesome inline icons: {[github]} / {[fa-solid:user]} — resolve
|
|
667
|
-
// against the FA catalog so unknown / ambiguous tokens stay as
|
|
668
|
-
// literal text (preserved through escapeHtml later). Stashing here
|
|
669
|
-
// alongside images/mentions keeps the `_` and other punctuation in
|
|
670
|
-
// the class attribute from being mangled by the underscore-italic
|
|
671
|
-
// regex below.
|
|
672
|
-
staged = staged.replace(RE_ICON_MD, (full, token) => {
|
|
673
|
-
const icon = resolveIcon(token);
|
|
674
|
-
if (!icon)
|
|
675
|
-
return full; // leave literal text — author may have meant it
|
|
676
|
-
return stash(`<i class="fa-${icon.family} fa-${icon.name}" data-icon="${escapeHtml(token)}" data-family="${icon.family}" data-name="${icon.name}" contenteditable="false"></i>`);
|
|
677
|
-
});
|
|
678
|
-
// Links: [text](url) — stash but keep the link text available to
|
|
679
|
-
// inline formatting by recursing.
|
|
680
|
-
staged = staged.replace(RE_LINK, (_m, linkText, href) => stash(`<a href="${escapeHtml(href)}">${inlineToHtml(linkText)}</a>`));
|
|
681
|
-
let result = escapeHtml(staged);
|
|
682
|
-
// Bold: **text** or __text__
|
|
683
|
-
result = result.replace(RE_BOLD_STAR, '<strong>$1</strong>');
|
|
684
|
-
result = result.replace(RE_BOLD_UNDER, '<strong>$1</strong>');
|
|
685
|
-
// Italic: *text* or _text_
|
|
686
|
-
result = result.replace(RE_ITALIC_STAR, '<em>$1</em>');
|
|
687
|
-
result = result.replace(RE_ITALIC_UNDER, '<em>$1</em>');
|
|
688
|
-
// Strikethrough: ~~text~~
|
|
689
|
-
result = result.replace(RE_STRIKETHROUGH, '<s>$1</s>');
|
|
690
|
-
// Inline code: `text`
|
|
691
|
-
result = result.replace(RE_INLINE_CODE, '<code>$1</code>');
|
|
692
|
-
// Restore placeholders. escapeHtml turned each `\u0000PHn\u0000` into
|
|
693
|
-
// the same string (the NULs and digits are escape-safe), so the
|
|
694
|
-
// restoration regex still matches.
|
|
695
|
-
// eslint-disable-next-line no-control-regex
|
|
696
|
-
result = result.replace(/\u0000PH(\d+)\u0000/g, (_m, idx) => placeholders[Number(idx)] ?? '');
|
|
697
|
-
return result;
|
|
698
|
-
}
|
|
699
|
-
/** Convert inline HTML back to markdown */
|
|
700
|
-
function htmlToInline(html) {
|
|
701
|
-
let result = html;
|
|
702
|
-
// Soft line breaks — convert <br> to GFM hard-break syntax (two trailing
|
|
703
|
-
// spaces + newline) before stripping tags so the newline survives.
|
|
704
|
-
result = result.replace(/<br\s*\/?>/gi, ' \n');
|
|
705
|
-
// FontAwesome inline icons — emit the original token. Must run before
|
|
706
|
-
// RE_I_TAG (which matches a bare `<i>` and would otherwise eat icon
|
|
707
|
-
// tags too). The token captured via data-icon already carries the
|
|
708
|
-
// qualified form when needed, so source round-trips exactly.
|
|
709
|
-
result = result.replace(RE_ICON_TAG, (_m, token) => `{[${token}]}`);
|
|
710
|
-
// Strong
|
|
711
|
-
result = result.replace(RE_STRONG_TAG, '**$1**');
|
|
712
|
-
result = result.replace(RE_B_TAG, '**$1**');
|
|
713
|
-
// Em
|
|
714
|
-
result = result.replace(RE_EM_TAG, '*$1*');
|
|
715
|
-
result = result.replace(RE_I_TAG, '*$1*');
|
|
716
|
-
// Strikethrough
|
|
717
|
-
result = result.replace(RE_S_TAG, '~~$1~~');
|
|
718
|
-
result = result.replace(RE_DEL_TAG, '~~$1~~');
|
|
719
|
-
// Code
|
|
720
|
-
result = result.replace(RE_CODE_TAG, '`$1`');
|
|
721
|
-
// Mentions — match before the link handler so the span isn't stripped
|
|
722
|
-
// out as an unknown tag. Pull kind + id out of the data attributes.
|
|
723
|
-
result = result.replace(RE_MENTION_TAG, (match, _inner) => {
|
|
724
|
-
const kind = /data-kind="([^"]*)"/i.exec(match)?.[1] ?? '';
|
|
725
|
-
const id = /data-id="([^"]*)"/i.exec(match)?.[1] ?? '';
|
|
726
|
-
const label = /data-label="([^"]*)"/i.exec(match)?.[1] ?? '';
|
|
727
|
-
if (!kind || !id || !label)
|
|
728
|
-
return match;
|
|
729
|
-
return `@[${label}](${kind}:${id})`;
|
|
730
|
-
});
|
|
731
|
-
// Links
|
|
732
|
-
result = result.replace(RE_A_TAG, '[$2]($1)');
|
|
733
|
-
// Images — order-agnostic attribute parsing (tiptap emits src-first,
|
|
734
|
-
// our markdown-to-html emits alt-first; either must serialize back).
|
|
735
|
-
// When a width/height is present we serialize as raw HTML `<img>` so
|
|
736
|
-
// the dimensions survive the round-trip; otherwise the markdown
|
|
737
|
-
// shorthand `` is used.
|
|
738
|
-
result = result.replace(RE_IMG_TAG, (match, attrs) => {
|
|
739
|
-
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1];
|
|
740
|
-
if (!src)
|
|
741
|
-
return match;
|
|
742
|
-
const alt = /\balt="([^"]*)"/i.exec(attrs)?.[1] ?? '';
|
|
743
|
-
return serializeImage(src, alt, attrs);
|
|
744
|
-
});
|
|
745
|
-
// Strip remaining tags
|
|
746
|
-
result = result.replace(RE_STRIP_TAGS, '');
|
|
747
|
-
return unescapeHtml(result);
|
|
748
|
-
}
|
|
749
|
-
//# sourceMappingURL=tiptapBridge.js.map
|