Skip to content

Commit f612334

Browse files
authored
Merge pull request #4609 from electroluxcode/fix/block-context-menu-stick
2 parents 6545a40 + 29afb9b commit f612334

File tree

3 files changed

+225
-214
lines changed

3 files changed

+225
-214
lines changed

apps/www/src/registry/ui/block-context-menu.tsx

Lines changed: 112 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
BlockSelectionPlugin,
1010
} from '@platejs/selection/react';
1111
import { KEYS } from 'platejs';
12-
import { useEditorPlugin, usePlateState } from 'platejs/react';
12+
import { useEditorPlugin, usePlateState, usePluginOption } from 'platejs/react';
1313

1414
import {
1515
ContextMenu,
@@ -30,6 +30,8 @@ export function BlockContextMenu({ children }: { children: React.ReactNode }) {
3030
const [value, setValue] = React.useState<Value>(null);
3131
const isTouch = useIsTouchDevice();
3232
const [readOnly] = usePlateState('readOnly');
33+
const openId = usePluginOption(BlockMenuPlugin, 'openId');
34+
const isOpen = openId === BLOCK_CONTEXT_MENU_ID;
3335

3436
const handleTurnInto = React.useCallback(
3537
(type: string) => {
@@ -66,10 +68,7 @@ export function BlockContextMenu({ children }: { children: React.ReactNode }) {
6668
<ContextMenu
6769
onOpenChange={(open) => {
6870
if (!open) {
69-
// prevent unselect the block selection
70-
setTimeout(() => {
71-
api.blockMenu.hide();
72-
}, 0);
71+
api.blockMenu.hide();
7372
}
7473
}}
7574
modal={false}
@@ -85,113 +84,119 @@ export function BlockContextMenu({ children }: { children: React.ReactNode }) {
8584

8685
if (disabled) return event.preventDefault();
8786

88-
api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {
89-
x: event.clientX,
90-
y: event.clientY,
91-
});
87+
setTimeout(() => {
88+
api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {
89+
x: event.clientX,
90+
y: event.clientY,
91+
});
92+
}, 0);
9293
}}
9394
>
9495
<div className="w-full">{children}</div>
9596
</ContextMenuTrigger>
96-
<ContextMenuContent
97-
className="w-64"
98-
onCloseAutoFocus={(e) => {
99-
e.preventDefault();
100-
editor.getApi(BlockSelectionPlugin).blockSelection.focus();
101-
102-
if (value === 'askAI') {
103-
editor.getApi(AIChatPlugin).aiChat.show();
104-
}
105-
106-
setValue(null);
107-
}}
108-
>
109-
<ContextMenuGroup>
110-
<ContextMenuItem
111-
onClick={() => {
112-
setValue('askAI');
113-
}}
114-
>
115-
Ask AI
116-
</ContextMenuItem>
117-
<ContextMenuItem
118-
onClick={() => {
119-
editor
120-
.getTransforms(BlockSelectionPlugin)
121-
.blockSelection.removeNodes();
122-
editor.tf.focus();
123-
}}
124-
>
125-
Delete
126-
</ContextMenuItem>
127-
<ContextMenuItem
128-
onClick={() => {
129-
editor
130-
.getTransforms(BlockSelectionPlugin)
131-
.blockSelection.duplicate();
132-
}}
133-
>
134-
Duplicate
135-
{/* <ContextMenuShortcut>⌘ + D</ContextMenuShortcut> */}
136-
</ContextMenuItem>
137-
<ContextMenuSub>
138-
<ContextMenuSubTrigger>Turn into</ContextMenuSubTrigger>
139-
<ContextMenuSubContent className="w-48">
140-
<ContextMenuItem onClick={() => handleTurnInto(KEYS.p)}>
141-
Paragraph
142-
</ContextMenuItem>
143-
144-
<ContextMenuItem onClick={() => handleTurnInto(KEYS.h1)}>
145-
Heading 1
146-
</ContextMenuItem>
147-
<ContextMenuItem onClick={() => handleTurnInto(KEYS.h2)}>
148-
Heading 2
149-
</ContextMenuItem>
150-
<ContextMenuItem onClick={() => handleTurnInto(KEYS.h3)}>
151-
Heading 3
152-
</ContextMenuItem>
153-
<ContextMenuItem onClick={() => handleTurnInto(KEYS.blockquote)}>
154-
Blockquote
155-
</ContextMenuItem>
156-
</ContextMenuSubContent>
157-
</ContextMenuSub>
158-
</ContextMenuGroup>
159-
160-
<ContextMenuGroup>
161-
<ContextMenuItem
162-
onClick={() =>
163-
editor
164-
.getTransforms(BlockSelectionPlugin)
165-
.blockSelection.setIndent(1)
97+
{isOpen && (
98+
<ContextMenuContent
99+
className="w-64"
100+
onCloseAutoFocus={(e) => {
101+
e.preventDefault();
102+
editor.getApi(BlockSelectionPlugin).blockSelection.focus();
103+
104+
if (value === 'askAI') {
105+
editor.getApi(AIChatPlugin).aiChat.show();
166106
}
167-
>
168-
Indent
169-
</ContextMenuItem>
170-
<ContextMenuItem
171-
onClick={() =>
172-
editor
173-
.getTransforms(BlockSelectionPlugin)
174-
.blockSelection.setIndent(-1)
175-
}
176-
>
177-
Outdent
178-
</ContextMenuItem>
179-
<ContextMenuSub>
180-
<ContextMenuSubTrigger>Align</ContextMenuSubTrigger>
181-
<ContextMenuSubContent className="w-48">
182-
<ContextMenuItem onClick={() => handleAlign('left')}>
183-
Left
184-
</ContextMenuItem>
185-
<ContextMenuItem onClick={() => handleAlign('center')}>
186-
Center
187-
</ContextMenuItem>
188-
<ContextMenuItem onClick={() => handleAlign('right')}>
189-
Right
190-
</ContextMenuItem>
191-
</ContextMenuSubContent>
192-
</ContextMenuSub>
193-
</ContextMenuGroup>
194-
</ContextMenuContent>
107+
108+
setValue(null);
109+
}}
110+
>
111+
<ContextMenuGroup>
112+
<ContextMenuItem
113+
onClick={() => {
114+
setValue('askAI');
115+
}}
116+
>
117+
Ask AI
118+
</ContextMenuItem>
119+
<ContextMenuItem
120+
onClick={() => {
121+
editor
122+
.getTransforms(BlockSelectionPlugin)
123+
.blockSelection.removeNodes();
124+
editor.tf.focus();
125+
}}
126+
>
127+
Delete
128+
</ContextMenuItem>
129+
<ContextMenuItem
130+
onClick={() => {
131+
editor
132+
.getTransforms(BlockSelectionPlugin)
133+
.blockSelection.duplicate();
134+
}}
135+
>
136+
Duplicate
137+
{/* <ContextMenuShortcut>⌘ + D</ContextMenuShortcut> */}
138+
</ContextMenuItem>
139+
<ContextMenuSub>
140+
<ContextMenuSubTrigger>Turn into</ContextMenuSubTrigger>
141+
<ContextMenuSubContent className="w-48">
142+
<ContextMenuItem onClick={() => handleTurnInto(KEYS.p)}>
143+
Paragraph
144+
</ContextMenuItem>
145+
146+
<ContextMenuItem onClick={() => handleTurnInto(KEYS.h1)}>
147+
Heading 1
148+
</ContextMenuItem>
149+
<ContextMenuItem onClick={() => handleTurnInto(KEYS.h2)}>
150+
Heading 2
151+
</ContextMenuItem>
152+
<ContextMenuItem onClick={() => handleTurnInto(KEYS.h3)}>
153+
Heading 3
154+
</ContextMenuItem>
155+
<ContextMenuItem
156+
onClick={() => handleTurnInto(KEYS.blockquote)}
157+
>
158+
Blockquote
159+
</ContextMenuItem>
160+
</ContextMenuSubContent>
161+
</ContextMenuSub>
162+
</ContextMenuGroup>
163+
164+
<ContextMenuGroup>
165+
<ContextMenuItem
166+
onClick={() =>
167+
editor
168+
.getTransforms(BlockSelectionPlugin)
169+
.blockSelection.setIndent(1)
170+
}
171+
>
172+
Indent
173+
</ContextMenuItem>
174+
<ContextMenuItem
175+
onClick={() =>
176+
editor
177+
.getTransforms(BlockSelectionPlugin)
178+
.blockSelection.setIndent(-1)
179+
}
180+
>
181+
Outdent
182+
</ContextMenuItem>
183+
<ContextMenuSub>
184+
<ContextMenuSubTrigger>Align</ContextMenuSubTrigger>
185+
<ContextMenuSubContent className="w-48">
186+
<ContextMenuItem onClick={() => handleAlign('left')}>
187+
Left
188+
</ContextMenuItem>
189+
<ContextMenuItem onClick={() => handleAlign('center')}>
190+
Center
191+
</ContextMenuItem>
192+
<ContextMenuItem onClick={() => handleAlign('right')}>
193+
Right
194+
</ContextMenuItem>
195+
</ContextMenuSubContent>
196+
</ContextMenuSub>
197+
</ContextMenuGroup>
198+
</ContextMenuContent>
199+
)}
195200
</ContextMenu>
196201
);
197202
}

docs/components/changelog.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Use the [CLI](https://platejs.org/docs/components/cli) to install the latest ver
1010

1111
## September 2025 #26
1212

13+
### September 7 #26.2
14+
- `block-context-menu`: Fixed menu position sticking when triggered multiple times in different locations
15+
1316
### September 5 #26.1
1417
- `block-draggable`: Fixed block selection to work with right-click events
1518

0 commit comments

Comments
 (0)