diff --git a/app/editor/components/FloatingToolbar.tsx b/app/editor/components/FloatingToolbar.tsx index 7778393bc..96327f336 100644 --- a/app/editor/components/FloatingToolbar.tsx +++ b/app/editor/components/FloatingToolbar.tsx @@ -37,7 +37,13 @@ function usePosition({ const viewportHeight = useViewportHeight(); const isTouchDevice = useMediaQuery("(hover: none) and (pointer: coarse)"); - if (!active || !menuWidth || !menuHeight || isSelectingText) { + if ( + !active || + !menuWidth || + !menuHeight || + !menuRef.current || + isSelectingText + ) { return defaultPosition; } @@ -146,54 +152,54 @@ function usePosition({ } } -function FloatingToolbar(props: Props) { - const menuRef = props.forwardedRef || React.createRef(); - const [isSelectingText, setSelectingText] = React.useState(false); +const FloatingToolbar = React.forwardRef( + (props: Props, forwardedRef: React.RefObject) => { + const menuRef = forwardedRef || React.createRef(); + const [isSelectingText, setSelectingText] = React.useState(false); - const position = usePosition({ - menuRef, - isSelectingText, - props, - }); + const position = usePosition({ + menuRef, + isSelectingText, + props, + }); - React.useEffect(() => { - const handleMouseDown = () => { - if (!props.active) { - setSelectingText(true); - } - }; + React.useEffect(() => { + const handleMouseDown = () => { + if (!props.active) { + setSelectingText(true); + } + }; - const handleMouseUp = () => { - setSelectingText(false); - }; + const handleMouseUp = () => { + setSelectingText(false); + }; - window.addEventListener("mousedown", handleMouseDown); - window.addEventListener("mouseup", handleMouseUp); + window.addEventListener("mousedown", handleMouseDown); + window.addEventListener("mouseup", handleMouseUp); - return () => { - window.removeEventListener("mousedown", handleMouseDown); - window.removeEventListener("mouseup", handleMouseUp); - }; - }, [props.active]); + return () => { + window.removeEventListener("mousedown", handleMouseDown); + window.removeEventListener("mouseup", handleMouseUp); + }; + }, [props.active]); - // only render children when state is updated to visible - // to prevent gaining input focus before calculatePosition runs - return ( - - - {position.visible && props.children} - - - ); -} + return ( + + + {props.children} + + + ); + } +); const Wrapper = styled.div<{ active?: boolean; @@ -259,9 +265,4 @@ const Wrapper = styled.div<{ } `; -export default React.forwardRef(function FloatingToolbarWithForwardedRef( - props: Props, - ref: React.RefObject -) { - return ; -}); +export default FloatingToolbar; diff --git a/app/editor/components/SelectionToolbar.tsx b/app/editor/components/SelectionToolbar.tsx index 676e45da6..453f6b509 100644 --- a/app/editor/components/SelectionToolbar.tsx +++ b/app/editor/components/SelectionToolbar.tsx @@ -3,8 +3,8 @@ import { NodeSelection, TextSelection } from "prosemirror-state"; import { CellSelection } from "prosemirror-tables"; import { EditorView } from "prosemirror-view"; import * as React from "react"; -import { Portal } from "react-portal"; import createAndInsertLink from "@shared/editor/commands/createAndInsertLink"; +import { CommandFactory } from "@shared/editor/lib/Extension"; import filterExcessSeparators from "@shared/editor/lib/filterExcessSeparators"; import getColumnIndex from "@shared/editor/queries/getColumnIndex"; import getMarkRange from "@shared/editor/queries/getMarkRange"; @@ -27,7 +27,7 @@ type Props = { dictionary: Dictionary; rtl: boolean; isTemplate: boolean; - commands: Record; + commands: Record; onOpen: () => void; onClose: () => void; onSearchLink?: (term: string) => Promise; @@ -229,27 +229,25 @@ export default class SelectionToolbar extends React.Component { } return ( - - - {link && range ? ( - - ) : ( - - )} - - + + {link && range ? ( + + ) : ( + + )} + ); } } diff --git a/app/editor/components/ToolbarMenu.tsx b/app/editor/components/ToolbarMenu.tsx index 6320b7c40..670a9dd2a 100644 --- a/app/editor/components/ToolbarMenu.tsx +++ b/app/editor/components/ToolbarMenu.tsx @@ -1,6 +1,6 @@ import { EditorView } from "prosemirror-view"; import * as React from "react"; -import styled, { useTheme } from "styled-components"; +import styled from "styled-components"; import { CommandFactory } from "@shared/editor/lib/Extension"; import { MenuItem } from "@shared/editor/types"; import ToolbarButton from "./ToolbarButton"; @@ -14,12 +14,12 @@ type Props = { }; const FlexibleWrapper = styled.div` + color: ${(props) => props.theme.toolbarItem}; display: flex; gap: 8px; `; function ToolbarMenu(props: Props) { - const theme = useTheme(); const { view, items } = props; const { state } = view; @@ -36,13 +36,12 @@ function ToolbarMenu(props: Props) { const isActive = item.active ? item.active(state) : false; return ( - + item.name && props.commands[item.name](item.attrs)} active={isActive} > - + ); diff --git a/app/editor/index.tsx b/app/editor/index.tsx index e3015024f..7e0954b58 100644 --- a/app/editor/index.tsx +++ b/app/editor/index.tsx @@ -12,7 +12,7 @@ import { selectColumn, selectRow, selectTable } from "prosemirror-utils"; import { Decoration, EditorView } from "prosemirror-view"; import * as React from "react"; import { DefaultTheme, ThemeProps } from "styled-components"; -import Extension from "@shared/editor/lib/Extension"; +import Extension, { CommandFactory } from "@shared/editor/lib/Extension"; import ExtensionManager from "@shared/editor/lib/ExtensionManager"; import headingToSlug from "@shared/editor/lib/headingToSlug"; import { MarkdownSerializer } from "@shared/editor/lib/markdown/serializer"; @@ -219,7 +219,7 @@ export class Editor extends React.PureComponent< nodes: { [name: string]: NodeSpec }; marks: { [name: string]: MarkSpec }; - commands: Record; + commands: Record; rulePlugins: PluginSimple[]; componentDidMount() { diff --git a/app/hooks/useComponentSize.ts b/app/hooks/useComponentSize.ts index 77194caed..24d929ccc 100644 --- a/app/hooks/useComponentSize.ts +++ b/app/hooks/useComponentSize.ts @@ -4,8 +4,8 @@ export default function useComponentSize( ref: React.RefObject ): { width: number; height: number } { const [size, setSize] = useState({ - width: 0, - height: 0, + width: ref.current?.clientWidth || 0, + height: ref.current?.clientHeight || 0, }); useEffect(() => {