From 552c0ecf013df828f22b283c8fb68e9fd3a5f78b Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Wed, 16 Nov 2022 23:29:29 -0500 Subject: [PATCH] fix: Pasting document content in title should behave as expected --- app/components/ContentEditable.tsx | 4 +-- .../Document/components/EditableTitle.tsx | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/app/components/ContentEditable.tsx b/app/components/ContentEditable.tsx index 5d156365b..0f03546f2 100644 --- a/app/components/ContentEditable.tsx +++ b/app/components/ContentEditable.tsx @@ -118,8 +118,8 @@ const ContentEditable = React.forwardRef( } }, [value, contentRef]); - // Ensure only plain text can be pasted into title when pasting from another - // rich text editor + // Ensure only plain text can be pasted into input when pasting from another + // rich text source const handlePaste = React.useCallback( (event: React.ClipboardEvent) => { event.preventDefault(); diff --git a/app/scenes/Document/components/EditableTitle.tsx b/app/scenes/Document/components/EditableTitle.tsx index 6f6d30993..998f51286 100644 --- a/app/scenes/Document/components/EditableTitle.tsx +++ b/app/scenes/Document/components/EditableTitle.tsx @@ -1,4 +1,5 @@ import { observer } from "mobx-react"; +import { Selection } from "prosemirror-state"; import * as React from "react"; import styled from "styled-components"; import breakpoint from "styled-components-breakpoint"; @@ -11,6 +12,7 @@ import { import { DocumentValidation } from "@shared/validations"; import Document from "~/models/Document"; import ContentEditable, { RefHandle } from "~/components/ContentEditable"; +import { useDocumentContext } from "~/components/DocumentContext"; import Star, { AnimatedStar } from "~/components/Star"; import useEmojiWidth from "~/hooks/useEmojiWidth"; import { isModKey } from "~/utils/keyboard"; @@ -50,6 +52,7 @@ const EditableTitle = React.forwardRef( }: Props, ref: React.RefObject ) => { + const { editor } = useDocumentContext(); const handleClick = React.useCallback(() => { ref.current?.focus(); }, [ref]); @@ -112,6 +115,32 @@ const EditableTitle = React.forwardRef( [ref, onChange] ); + // Custom paste handling so that if a multiple lines are pasted we + // only take the first line and insert the rest directly into the editor. + const handlePaste = React.useCallback( + (event: React.ClipboardEvent) => { + event.preventDefault(); + const text = event.clipboardData.getData("text/plain"); + const [firstLine, ...rest] = text.split(`\n`); + const content = rest.join(`\n`).trim(); + window.document.execCommand( + "insertText", + false, + firstLine.replace(/^#+\s?/, "") + ); + + if (editor && content) { + const { view, parser } = editor; + view.dispatch( + view.state.tr + .setSelection(Selection.atStart(view.state.doc)) + .insert(0, parser.parse(content)) + ); + } + }, + [editor] + ); + const emojiWidth = useEmojiWidth(document.emoji, { fontSize, lineHeight, @@ -125,6 +154,7 @@ const EditableTitle = React.forwardRef( onClick={handleClick} onChange={handleChange} onKeyDown={handleKeyDown} + onPaste={handlePaste} onBlur={onBlur} placeholder={placeholder} value={value}