fix: preserve line breaks when pasting text in editor
This commit is contained in:
@@ -11,14 +11,14 @@ const DRAGOVER_CLASS_LIST = [
|
|||||||
'rounded-md'
|
'rounded-md'
|
||||||
]
|
]
|
||||||
|
|
||||||
export interface FileHandlerOptions {
|
export interface ClipboardAndDropHandlerOptions {
|
||||||
onUploadStart?: (file: File) => void
|
onUploadStart?: (file: File) => void
|
||||||
onUploadSuccess?: (file: File, result: any) => void
|
onUploadSuccess?: (file: File, result: any) => void
|
||||||
onUploadError?: (file: File, error: any) => void
|
onUploadError?: (file: File, error: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileHandler = Extension.create<FileHandlerOptions>({
|
export const ClipboardAndDropHandler = Extension.create<ClipboardAndDropHandlerOptions>({
|
||||||
name: 'fileHandler',
|
name: 'clipboardAndDropHandler',
|
||||||
|
|
||||||
addOptions() {
|
addOptions() {
|
||||||
return {
|
return {
|
||||||
@@ -61,17 +61,38 @@ export const FileHandler = Extension.create<FileHandlerOptions>({
|
|||||||
},
|
},
|
||||||
handlePaste(view, event) {
|
handlePaste(view, event) {
|
||||||
const items = Array.from(event.clipboardData?.items ?? [])
|
const items = Array.from(event.clipboardData?.items ?? [])
|
||||||
const mediaItem = items.find(
|
let handled = false
|
||||||
(item) => item.type.includes('image') || item.type.includes('video')
|
|
||||||
)
|
|
||||||
if (!mediaItem) return false
|
|
||||||
|
|
||||||
const file = mediaItem.getAsFile()
|
for (const item of items) {
|
||||||
if (!file) return false
|
if (
|
||||||
|
item.kind === 'file' &&
|
||||||
|
(item.type.includes('image') || item.type.includes('video'))
|
||||||
|
) {
|
||||||
|
const file = item.getAsFile()
|
||||||
|
if (file) {
|
||||||
|
uploadFile(view, file, options)
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
} else if (item.kind === 'string' && item.type === 'text/plain') {
|
||||||
|
item.getAsString((text) => {
|
||||||
|
const { schema } = view.state
|
||||||
|
const parts = text.split('\n')
|
||||||
|
const nodes = []
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
if (i > 0) nodes.push(schema.nodes.hardBreak.create())
|
||||||
|
if (parts[i]) nodes.push(schema.text(parts[i]))
|
||||||
|
}
|
||||||
|
const fragment = schema.nodes.paragraph.create(null, nodes)
|
||||||
|
const tr = view.state.tr.replaceSelectionWith(fragment)
|
||||||
|
view.dispatch(tr)
|
||||||
|
})
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
|
||||||
uploadFile(view, file, options)
|
// Only handle the first file/string item
|
||||||
|
if (handled) break
|
||||||
return true
|
}
|
||||||
|
return handled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -79,7 +100,7 @@ export const FileHandler = Extension.create<FileHandlerOptions>({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
async function uploadFile(view: EditorView, file: File, options: FileHandlerOptions) {
|
async function uploadFile(view: EditorView, file: File, options: ClipboardAndDropHandlerOptions) {
|
||||||
const name = file.name
|
const name = file.name
|
||||||
|
|
||||||
options.onUploadStart?.(file)
|
options.onUploadStart?.(file)
|
||||||
@@ -2,6 +2,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
|||||||
import { parseEditorJsonToText } from '@/lib/tiptap'
|
import { parseEditorJsonToText } from '@/lib/tiptap'
|
||||||
import postContentCache from '@/services/post-content-cache.service'
|
import postContentCache from '@/services/post-content-cache.service'
|
||||||
import Document from '@tiptap/extension-document'
|
import Document from '@tiptap/extension-document'
|
||||||
|
import { HardBreak } from '@tiptap/extension-hard-break'
|
||||||
import History from '@tiptap/extension-history'
|
import History from '@tiptap/extension-history'
|
||||||
import Paragraph from '@tiptap/extension-paragraph'
|
import Paragraph from '@tiptap/extension-paragraph'
|
||||||
import Placeholder from '@tiptap/extension-placeholder'
|
import Placeholder from '@tiptap/extension-placeholder'
|
||||||
@@ -12,8 +13,8 @@ import { Event } from 'nostr-tools'
|
|||||||
import { Dispatch, forwardRef, SetStateAction, useImperativeHandle } from 'react'
|
import { Dispatch, forwardRef, SetStateAction, useImperativeHandle } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { usePostEditor } from '../PostEditorProvider'
|
import { usePostEditor } from '../PostEditorProvider'
|
||||||
|
import { ClipboardAndDropHandler } from './ClipboardAndDropHandler'
|
||||||
import CustomMention from './CustomMention'
|
import CustomMention from './CustomMention'
|
||||||
import { FileHandler } from './FileHandler'
|
|
||||||
import Preview from './Preview'
|
import Preview from './Preview'
|
||||||
import suggestion from './suggestion'
|
import suggestion from './suggestion'
|
||||||
|
|
||||||
@@ -40,13 +41,14 @@ const PostTextarea = forwardRef<
|
|||||||
Paragraph,
|
Paragraph,
|
||||||
Text,
|
Text,
|
||||||
History,
|
History,
|
||||||
|
HardBreak,
|
||||||
Placeholder.configure({
|
Placeholder.configure({
|
||||||
placeholder: t('Write something...') + ' (' + t('Paste or drop media files to upload') + ')'
|
placeholder: t('Write something...') + ' (' + t('Paste or drop media files to upload') + ')'
|
||||||
}),
|
}),
|
||||||
CustomMention.configure({
|
CustomMention.configure({
|
||||||
suggestion
|
suggestion
|
||||||
}),
|
}),
|
||||||
FileHandler.configure({
|
ClipboardAndDropHandler.configure({
|
||||||
onUploadStart: () => setUploadingFiles((prev) => prev + 1),
|
onUploadStart: () => setUploadingFiles((prev) => prev + 1),
|
||||||
onUploadSuccess: () => setUploadingFiles((prev) => prev - 1),
|
onUploadSuccess: () => setUploadingFiles((prev) => prev - 1),
|
||||||
onUploadError: () => setUploadingFiles((prev) => prev - 1)
|
onUploadError: () => setUploadingFiles((prev) => prev - 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user