diff --git a/app/components/ContentEditable.tsx b/app/components/ContentEditable.tsx index 00635a283..984446ea0 100644 --- a/app/components/ContentEditable.tsx +++ b/app/components/ContentEditable.tsx @@ -81,6 +81,17 @@ const ContentEditable = React.forwardRef( } }, [value, ref]); + // Ensure only plain text can be pasted into title when pasting from another + // rich text editor + const handlePaste = React.useCallback( + (event: React.ClipboardEvent) => { + event.preventDefault(); + const text = event.clipboardData.getData("text/plain"); + window.document.execCommand("insertText", false, text); + }, + [] + ); + return (
props.theme.background}; + transition: ${(props) => props.theme.backgroundTransition}; + color: ${(props) => props.theme.text}; + -webkit-text-fill-color: ${(props) => props.theme.text}; + outline: none; + resize: none; + cursor: text; + &:empty { display: inline-block; } diff --git a/app/components/Heading.ts b/app/components/Heading.ts index c87873e33..3b4b96575 100644 --- a/app/components/Heading.ts +++ b/app/components/Heading.ts @@ -5,14 +5,6 @@ const Heading = styled.h1<{ centered?: boolean }>` align-items: center; user-select: none; ${(props) => (props.centered ? "text-align: center;" : "")} - - svg { - margin-top: 4px; - margin-left: -6px; - margin-right: 2px; - align-self: flex-start; - flex-shrink: 0; - } `; export default Heading; diff --git a/app/hooks/useEmojiWidth.ts b/app/hooks/useEmojiWidth.ts new file mode 100644 index 000000000..5a3ed95bc --- /dev/null +++ b/app/hooks/useEmojiWidth.ts @@ -0,0 +1,33 @@ +import * as React from "react"; + +type Options = { + fontSize?: string; + lineHeight?: string; +}; + +/** + * Measures the width of an emoji character + */ +export default function useEmojiWidth( + emoji: string | undefined, + { fontSize = "2.25em", lineHeight = "1.25" }: Options +) { + return React.useMemo(() => { + const element = window.document.createElement("span"); + if (!emoji) { + return 0; + } + + element.innerText = `${emoji}\u00A0`; + element.style.visibility = "hidden"; + element.style.position = "absolute"; + element.style.left = "-9999px"; + element.style.lineHeight = lineHeight; + element.style.fontSize = fontSize; + element.style.width = "max-content"; + window.document.body?.appendChild(element); + const width = window.getComputedStyle(element).width; + window.document.body?.removeChild(element); + return parseInt(width, 10); + }, [emoji, fontSize, lineHeight]); +} diff --git a/app/scenes/Collection.tsx b/app/scenes/Collection.tsx index 1b20bca04..164b20b04 100644 --- a/app/scenes/Collection.tsx +++ b/app/scenes/Collection.tsx @@ -9,6 +9,8 @@ import { useHistory, useRouteMatch, } from "react-router-dom"; +import styled from "styled-components"; +import breakpoint from "styled-components-breakpoint"; import Collection from "~/models/Collection"; import Search from "~/scenes/Search"; import Badge from "~/components/Badge"; @@ -107,8 +109,7 @@ function CollectionScene() { title={ <> -   - {collection.name} +  {collection.name} } actions={} @@ -123,9 +124,9 @@ function CollectionScene() { ) : ( <> - - {" "} - {collection.name}{" "} + + + {collection.name} {!collection.permission && ( {t("Private")} )} - + ) => { - event.preventDefault(); - const text = event.clipboardData.getData("text/plain"); - window.document.execCommand("insertText", false, text); - }, - [] - ); - const handleKeyDown = React.useCallback( (event: React.KeyboardEvent) => { if (event.key === "Enter") { @@ -102,34 +92,16 @@ const EditableTitle = React.forwardRef( [onGoToNextInput, onSave] ); - /** - * Measures the width of the document's emoji in the title - */ - const emojiWidth = React.useMemo(() => { - const element = window.document.createElement("span"); - if (!document.emoji) { - return 0; - } - - element.innerText = `${document.emoji}\u00A0`; - element.style.visibility = "hidden"; - element.style.position = "absolute"; - element.style.left = "-9999px"; - element.style.lineHeight = lineHeight; - element.style.fontSize = fontSize; - element.style.width = "max-content"; - window.document.body?.appendChild(element); - const width = window.getComputedStyle(element).width; - window.document.body?.removeChild(element); - return parseInt(width, 10); - }, [document.emoji]); + const emojiWidth = useEmojiWidth(document.emoji, { + fontSize, + lineHeight, + }); return ( ` line-height: ${lineHeight}; margin-top: 1em; margin-bottom: 0.5em; - background: ${(props) => props.theme.background}; - transition: ${(props) => props.theme.backgroundTransition}; - color: ${(props) => props.theme.text}; - -webkit-text-fill-color: ${(props) => props.theme.text}; font-size: ${fontSize}; font-weight: 500; - outline: none; border: 0; padding: 0; - resize: none; - cursor: text; > span { outline: none;