Skip to content

Commit ef8c8f0

Browse files
authored
Merge pull request #2480 from zetkin/undocumented/zui-editor-overlays-fixes
Improvements to `ZUIEditor` overlays
2 parents 21b0d81 + 0aabdfc commit ef8c8f0

File tree

6 files changed

+89
-31
lines changed

6 files changed

+89
-31
lines changed

src/zui/ZUIEditor/EditorOverlays/BlockInsert.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ type BlockInsertProps = {
1212
};
1313

1414
const BlockInsert: FC<BlockInsertProps> = ({ blockDividers, mouseY }) => {
15-
const { insertParagraph, focus } = useCommands();
15+
const { insertEmptyParagraph, focus } = useCommands();
1616

1717
return (
1818
<Box position="relative">
1919
{blockDividers.map(({ pos, y }, index) => {
2020
const visible = Math.abs(mouseY - y) < 20;
21-
const isFirst = index == 0;
22-
const offset = isFirst ? -6 : 12;
21+
const offset = 8;
22+
2323
return (
2424
<Box
2525
key={index}
@@ -44,9 +44,8 @@ const BlockInsert: FC<BlockInsertProps> = ({ blockDividers, mouseY }) => {
4444
>
4545
<Paper>
4646
<IconButton
47-
disabled={!insertParagraph.enabled(' ', { selection: pos })}
4847
onClick={() => {
49-
insertParagraph(' ', { selection: pos });
48+
insertEmptyParagraph(pos);
5049
focus(pos);
5150
}}
5251
>

src/zui/ZUIEditor/EditorOverlays/index.tsx

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
usePositioner,
66
} from '@remirror/react';
77
import { FC, useCallback, useEffect, useState } from 'react';
8+
import { ProsemirrorNode } from '@remirror/pm/suggest';
89
import { Box } from '@mui/material';
910

1011
import BlockToolbar from './BlockToolbar';
@@ -18,6 +19,7 @@ export type BlockDividerData = {
1819
};
1920

2021
type BlockData = {
22+
node: ProsemirrorNode;
2123
rect: DOMRect;
2224
type: string;
2325
};
@@ -63,6 +65,7 @@ const EditorOverlays: FC<Props> = ({
6365
const x = nodeRect.x - editorRect.x;
6466
const y = nodeRect.y - editorRect.y;
6567
setCurrentBlock({
68+
node,
6669
rect: {
6770
...nodeRect.toJSON(),
6871
left: x,
@@ -114,22 +117,35 @@ const EditorOverlays: FC<Props> = ({
114117
const blockDividers: BlockDividerData[] = [
115118
{
116119
pos: 0,
117-
y: 0,
120+
y: 8,
118121
},
119-
...state.doc.children.map((blockNode) => {
120-
pos += blockNode.nodeSize;
121-
const rect = view.coordsAtPos(pos - 1);
122+
];
123+
124+
const containerRect = view.dom.getBoundingClientRect();
125+
state.doc.children.forEach((blockNode) => {
126+
const elem = view.nodeDOM(pos);
127+
128+
pos += blockNode.nodeSize;
129+
130+
if (elem instanceof HTMLElement) {
131+
if (elem.nodeName == 'P' && elem.textContent?.trim().length == 0) {
132+
return;
133+
}
122134

123-
const containerRect = view.dom.getBoundingClientRect();
135+
const rect = elem.getBoundingClientRect();
124136

125-
return {
126-
pos: pos,
137+
blockDividers.push({
138+
pos,
127139
y: rect.bottom - containerRect.top,
128-
};
129-
}),
130-
];
140+
});
141+
}
142+
});
143+
144+
const isEmptyParagraph =
145+
currentBlock?.type == 'paragraph' && currentBlock?.node.textContent == '';
131146

132-
const showBlockToolbar = !showBlockMenu && !!currentBlock && !typing;
147+
const showBlockToolbar =
148+
!showBlockMenu && !!currentBlock && !typing && !isEmptyParagraph;
133149

134150
const showBlockInsert = !showBlockMenu && !typing;
135151

@@ -141,12 +157,15 @@ const EditorOverlays: FC<Props> = ({
141157
<Box position="relative">
142158
<Box
143159
border={1}
144-
height={currentBlock?.rect.height}
145-
left={currentBlock?.rect.left}
160+
height={currentBlock?.rect.height + 16}
161+
left={currentBlock?.rect.left - 8}
146162
position="absolute"
147-
sx={{ pointerEvents: 'none' }}
148-
top={currentBlock?.rect.top}
149-
width={currentBlock?.rect.width}
163+
sx={{
164+
opacity: 0.5,
165+
pointerEvents: 'none',
166+
}}
167+
top={currentBlock?.rect.top - 8}
168+
width={currentBlock?.rect.width + 16}
150169
/>
151170
</Box>
152171
)}

src/zui/ZUIEditor/EmptyBlockPlaceholder.tsx

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,50 @@
1-
import { Box, Typography } from '@mui/material';
2-
import { usePositioner } from '@remirror/react';
1+
import { Box, Link, Typography } from '@mui/material';
2+
import { useCommands, usePositioner } from '@remirror/react';
33
import { FC } from 'react';
44

5-
type Props = {
6-
placeholder: string;
7-
};
5+
import { Msg } from 'core/i18n';
6+
import messageIds from 'zui/l10n/messageIds';
87

9-
const EmptyBlockPlaceholder: FC<Props> = ({ placeholder }) => {
8+
const EmptyBlockPlaceholder: FC = () => {
109
const positioner = usePositioner('emptyBlockStart');
10+
const { focus, insertText } = useCommands();
1111

1212
return (
1313
<Box ref={positioner.ref} position="relative">
1414
{positioner.active && (
1515
<Typography
1616
sx={{
17+
'&:hover': {
18+
opacity: 1,
19+
},
1720
left: positioner.x,
1821
opacity: 0.5,
19-
pointerEvents: 'none',
2022
position: 'absolute',
2123
top: positioner.y,
24+
transition: 'opacity 0.5s',
2225
}}
2326
>
24-
{placeholder}
27+
<Msg
28+
id={messageIds.editor.placeholder.label}
29+
values={{
30+
link: (
31+
<Link
32+
onClick={() => {
33+
const pos = positioner.data.pos;
34+
if (pos) {
35+
insertText('/', { from: positioner.data.pos });
36+
focus(pos + 2);
37+
}
38+
}}
39+
sx={{
40+
cursor: 'pointer',
41+
}}
42+
>
43+
<Msg id={messageIds.editor.placeholder.link} />
44+
</Link>
45+
),
46+
}}
47+
/>
2548
</Typography>
2649
)}
2750
</Box>

src/zui/ZUIEditor/extensions/BlockMenuExtension.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Handler,
77
PlainExtension,
88
} from 'remirror';
9+
import { ParagraphExtension } from 'remirror/extensions';
910

1011
type BlockMenuOptions = {
1112
blockFactories: Record<string, CommandFunction>;
@@ -53,6 +54,17 @@ class BlockMenuExtension extends PlainExtension<BlockMenuOptions> {
5354
};
5455
}
5556

57+
/* eslint-disable @typescript-eslint/ban-ts-comment */
58+
//@ts-ignore
59+
@command()
60+
insertEmptyParagraph(pos: number): CommandFunction {
61+
return ({ dispatch, tr }) => {
62+
const node = this.store.getExtension(ParagraphExtension).type.create();
63+
dispatch?.(tr.insert(pos, node));
64+
return true;
65+
};
66+
}
67+
5668
get name(): string {
5769
return 'zblockmenu';
5870
}

src/zui/ZUIEditor/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ const ZUIEditor: FC<Props> = ({
196196
enableLink={!!enableLink}
197197
enableVariable={!!enableVariable}
198198
/>
199-
<EmptyBlockPlaceholder placeholder={messages.placeholder()} />
199+
<EmptyBlockPlaceholder />
200200
{enableImage && <ImageExtensionUI orgId={orgId} />}
201201
<ButtonExtensionUI />
202202
<LinkExtensionUI />

src/zui/l10n/messageIds.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,12 @@ export default makeMessages('zui', {
145145
textPlaceholder: m('Add link text here'),
146146
},
147147
},
148-
placeholder: m('Type / to insert block or just type some text'),
148+
placeholder: {
149+
label: m<{ link: ReactElement }>(
150+
'Type / or {link} to insert block, or just type some text'
151+
),
152+
link: m('click here'),
153+
},
149154
variables: {
150155
firstName: m('First Name'),
151156
fullName: m('Full Name'),

0 commit comments

Comments
 (0)