diff --git a/src/zui/ZUIEditor/EditorOverlays/BlockInsert.tsx b/src/zui/ZUIEditor/EditorOverlays/BlockInsert.tsx index df58ab535..fc9df5b06 100644 --- a/src/zui/ZUIEditor/EditorOverlays/BlockInsert.tsx +++ b/src/zui/ZUIEditor/EditorOverlays/BlockInsert.tsx @@ -12,14 +12,14 @@ type BlockInsertProps = { }; const BlockInsert: FC = ({ blockDividers, mouseY }) => { - const { insertParagraph, focus } = useCommands(); + const { insertEmptyParagraph, focus } = useCommands(); return ( {blockDividers.map(({ pos, y }, index) => { const visible = Math.abs(mouseY - y) < 20; - const isFirst = index == 0; - const offset = isFirst ? -6 : 12; + const offset = 8; + return ( = ({ blockDividers, mouseY }) => { > { - insertParagraph(' ', { selection: pos }); + insertEmptyParagraph(pos); focus(pos); }} > diff --git a/src/zui/ZUIEditor/EditorOverlays/index.tsx b/src/zui/ZUIEditor/EditorOverlays/index.tsx index 8dfeaba9c..0730da497 100644 --- a/src/zui/ZUIEditor/EditorOverlays/index.tsx +++ b/src/zui/ZUIEditor/EditorOverlays/index.tsx @@ -5,6 +5,7 @@ import { usePositioner, } from '@remirror/react'; import { FC, useCallback, useEffect, useState } from 'react'; +import { ProsemirrorNode } from '@remirror/pm/suggest'; import { Box } from '@mui/material'; import BlockToolbar from './BlockToolbar'; @@ -18,6 +19,7 @@ export type BlockDividerData = { }; type BlockData = { + node: ProsemirrorNode; rect: DOMRect; type: string; }; @@ -63,6 +65,7 @@ const EditorOverlays: FC = ({ const x = nodeRect.x - editorRect.x; const y = nodeRect.y - editorRect.y; setCurrentBlock({ + node, rect: { ...nodeRect.toJSON(), left: x, @@ -114,22 +117,35 @@ const EditorOverlays: FC = ({ const blockDividers: BlockDividerData[] = [ { pos: 0, - y: 0, + y: 8, }, - ...state.doc.children.map((blockNode) => { - pos += blockNode.nodeSize; - const rect = view.coordsAtPos(pos - 1); + ]; + + const containerRect = view.dom.getBoundingClientRect(); + state.doc.children.forEach((blockNode) => { + const elem = view.nodeDOM(pos); + + pos += blockNode.nodeSize; + + if (elem instanceof HTMLElement) { + if (elem.nodeName == 'P' && elem.textContent?.trim().length == 0) { + return; + } - const containerRect = view.dom.getBoundingClientRect(); + const rect = elem.getBoundingClientRect(); - return { - pos: pos, + blockDividers.push({ + pos, y: rect.bottom - containerRect.top, - }; - }), - ]; + }); + } + }); + + const isEmptyParagraph = + currentBlock?.type == 'paragraph' && currentBlock?.node.textContent == ''; - const showBlockToolbar = !showBlockMenu && !!currentBlock && !typing; + const showBlockToolbar = + !showBlockMenu && !!currentBlock && !typing && !isEmptyParagraph; const showBlockInsert = !showBlockMenu && !typing; @@ -141,12 +157,15 @@ const EditorOverlays: FC = ({ )} diff --git a/src/zui/ZUIEditor/EmptyBlockPlaceholder.tsx b/src/zui/ZUIEditor/EmptyBlockPlaceholder.tsx index 9a877409a..13d7fd5f4 100644 --- a/src/zui/ZUIEditor/EmptyBlockPlaceholder.tsx +++ b/src/zui/ZUIEditor/EmptyBlockPlaceholder.tsx @@ -1,27 +1,50 @@ -import { Box, Typography } from '@mui/material'; -import { usePositioner } from '@remirror/react'; +import { Box, Link, Typography } from '@mui/material'; +import { useCommands, usePositioner } from '@remirror/react'; import { FC } from 'react'; -type Props = { - placeholder: string; -}; +import { Msg } from 'core/i18n'; +import messageIds from 'zui/l10n/messageIds'; -const EmptyBlockPlaceholder: FC = ({ placeholder }) => { +const EmptyBlockPlaceholder: FC = () => { const positioner = usePositioner('emptyBlockStart'); + const { focus, insertText } = useCommands(); return ( {positioner.active && ( - {placeholder} + { + const pos = positioner.data.pos; + if (pos) { + insertText('/', { from: positioner.data.pos }); + focus(pos + 2); + } + }} + sx={{ + cursor: 'pointer', + }} + > + + + ), + }} + /> )} diff --git a/src/zui/ZUIEditor/extensions/BlockMenuExtension.ts b/src/zui/ZUIEditor/extensions/BlockMenuExtension.ts index 009add59a..ed94faca4 100644 --- a/src/zui/ZUIEditor/extensions/BlockMenuExtension.ts +++ b/src/zui/ZUIEditor/extensions/BlockMenuExtension.ts @@ -6,6 +6,7 @@ import { Handler, PlainExtension, } from 'remirror'; +import { ParagraphExtension } from 'remirror/extensions'; type BlockMenuOptions = { blockFactories: Record; @@ -53,6 +54,17 @@ class BlockMenuExtension extends PlainExtension { }; } + /* eslint-disable @typescript-eslint/ban-ts-comment */ + //@ts-ignore + @command() + insertEmptyParagraph(pos: number): CommandFunction { + return ({ dispatch, tr }) => { + const node = this.store.getExtension(ParagraphExtension).type.create(); + dispatch?.(tr.insert(pos, node)); + return true; + }; + } + get name(): string { return 'zblockmenu'; } diff --git a/src/zui/ZUIEditor/index.tsx b/src/zui/ZUIEditor/index.tsx index d1b1cf8ab..7748d83e9 100644 --- a/src/zui/ZUIEditor/index.tsx +++ b/src/zui/ZUIEditor/index.tsx @@ -196,7 +196,7 @@ const ZUIEditor: FC = ({ enableLink={!!enableLink} enableVariable={!!enableVariable} /> - + {enableImage && } diff --git a/src/zui/l10n/messageIds.ts b/src/zui/l10n/messageIds.ts index 3d8ca1d35..545bb2e49 100644 --- a/src/zui/l10n/messageIds.ts +++ b/src/zui/l10n/messageIds.ts @@ -145,7 +145,12 @@ export default makeMessages('zui', { textPlaceholder: m('Add link text here'), }, }, - placeholder: m('Type / to insert block or just type some text'), + placeholder: { + label: m<{ link: ReactElement }>( + 'Type / or {link} to insert block, or just type some text' + ), + link: m('click here'), + }, variables: { firstName: m('First Name'), fullName: m('Full Name'),