Block Context Menu
plate/block-context-menuFreeComponent
A context menu for block-level operations.
Live preview
live · rendered by the registry
Rendered by plate on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://platejs.org/r/block-context-menu.jsonSource
1'use client';23import * as React from 'react';45import { AIChatPlugin } from '@platejs/ai/react';6import {7 BLOCK_CONTEXT_MENU_ID,8 BlockMenuPlugin,9 BlockSelectionPlugin,10} from '@platejs/selection/react';11import { KEYS } from 'platejs';12import {13 useEditorPlugin,14 useEditorReadOnly,15 usePluginOption,16} from 'platejs/react';1718import {19 ContextMenu,20 ContextMenuContent,21 ContextMenuGroup,22 ContextMenuItem,23 ContextMenuSub,24 ContextMenuSubContent,25 ContextMenuSubTrigger,26 ContextMenuTrigger,27} from '@/components/ui/context-menu';28import { setBlockType } from '@/registry/components/editor/transforms';29import { useIsTouchDevice } from '@/registry/hooks/use-is-touch-device';3031type Value = 'askAI' | null;3233export function BlockContextMenu({ children }: { children: React.ReactNode }) {34 const { api, editor } = useEditorPlugin(BlockMenuPlugin);35 const [value, setValue] = React.useState<Value>(null);36 const isTouch = useIsTouchDevice();37 const readOnly = useEditorReadOnly();38 const openId = usePluginOption(BlockMenuPlugin, 'openId');39 const isOpen = openId === BLOCK_CONTEXT_MENU_ID;4041 const handleTurnInto = React.useCallback(42 (type: string) => {43 editor44 .getApi(BlockSelectionPlugin)45 .blockSelection.getNodes()46 .forEach(([, path]) => {47 setBlockType(editor, type, { at: path });48 });49 },50 [editor]51 );5253 const handleAlign = React.useCallback(54 (align: 'center' | 'left' | 'right') => {55 editor56 .getTransforms(BlockSelectionPlugin)57 .blockSelection.setNodes({ align });58 },59 [editor]60 );6162 if (isTouch) {63 return children;64 }6566 return (67 <ContextMenu68 onOpenChange={(open) => {69 if (!open) {70 api.blockMenu.hide();71 }72 }}73 modal={false}74 >75 <ContextMenuTrigger76 asChild77 onContextMenu={(event) => {78 const dataset = (event.target as HTMLElement).dataset;79 const disabled =80 dataset?.slateEditor === 'true' ||81 readOnly ||82 dataset?.plateOpenContextMenu === 'false';8384 if (disabled) return event.preventDefault();8586 setTimeout(() => {87 api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {88 x: event.clientX,89 y: event.clientY,90 });91 }, 0);92 }}93 >94 <div className="w-full">{children}</div>95 </ContextMenuTrigger>96 {isOpen && (97 <ContextMenuContent98// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from plate
All 324 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| ai-kitai-kit | plate | Components | Free | 1 dep | |
| AI Menuai-menu | plate | Components | Free | 5 deps · 2 files | |
| AI Leafai-node | plate | Components | Free | no deps | |
| AI Toolbar Buttonai-toolbar-button | plate | Components | Free | 1 dep | |
| align-base-kitalign-base-kit | plate | Components | Free | 1 dep | |
| align-kitalign-kit | plate | Components | Free | 1 dep | |
| Align Toolbar Buttonalign-toolbar-button | plate | Components | Free | 1 dep | |
| autoformat-classic-kitautoformat-classic-kit | plate | Components | Free | 2 deps |
