+ "content": "'use client';\n\nimport * as React from 'react';\n\nimport { AIChatPlugin } from '@platejs/ai/react';\nimport {\n BLOCK_CONTEXT_MENU_ID,\n BlockMenuPlugin,\n BlockSelectionPlugin,\n} from '@platejs/selection/react';\nimport { KEYS } from 'platejs';\nimport { useEditorPlugin, usePlateState, usePluginOption } from 'platejs/react';\n\nimport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from '@/components/ui/context-menu';\nimport { useIsTouchDevice } from '@/registry/hooks/use-is-touch-device';\n\ntype Value = 'askAI' | null;\n\nexport function BlockContextMenu({ children }: { children: React.ReactNode }) {\n const { api, editor } = useEditorPlugin(BlockMenuPlugin);\n const [value, setValue] = React.useState<Value>(null);\n const isTouch = useIsTouchDevice();\n const [readOnly] = usePlateState('readOnly');\n const openId = usePluginOption(BlockMenuPlugin, 'openId');\n const isOpen = openId === BLOCK_CONTEXT_MENU_ID;\n\n const handleTurnInto = React.useCallback(\n (type: string) => {\n editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes()\n .forEach(([node, path]) => {\n if (node[KEYS.listType]) {\n editor.tf.unsetNodes([KEYS.listType, 'indent'], {\n at: path,\n });\n }\n\n editor.tf.toggleBlock(type, { at: path });\n });\n },\n [editor]\n );\n\n const handleAlign = React.useCallback(\n (align: 'center' | 'left' | 'right') => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setNodes({ align });\n },\n [editor]\n );\n\n if (isTouch) {\n return children;\n }\n\n return (\n <ContextMenu\n onOpenChange={(open) => {\n if (!open) {\n api.blockMenu.hide();\n }\n }}\n modal={false}\n >\n <ContextMenuTrigger\n asChild\n onContextMenu={(event) => {\n const dataset = (event.target as HTMLElement).dataset;\n const disabled =\n dataset?.slateEditor === 'true' ||\n readOnly ||\n dataset?.plateOpenContextMenu === 'false';\n\n if (disabled) return event.preventDefault();\n\n setTimeout(() => {\n api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {\n x: event.clientX,\n y: event.clientY,\n });\n }, 0);\n }}\n >\n <div className=\"w-full\">{children}</div>\n </ContextMenuTrigger>\n {isOpen && (\n <ContextMenuContent\n className=\"w-64\"\n onCloseAutoFocus={(e) => {\n e.preventDefault();\n editor.getApi(BlockSelectionPlugin).blockSelection.focus();\n\n if (value === 'askAI') {\n editor.getApi(AIChatPlugin).aiChat.show();\n }\n\n setValue(null);\n }}\n >\n <ContextMenuGroup>\n <ContextMenuItem\n onClick={() => {\n setValue('askAI');\n }}\n >\n Ask AI\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.removeNodes();\n editor.tf.focus();\n }}\n >\n Delete\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.duplicate();\n }}\n >\n Duplicate\n {/* <ContextMenuShortcut>⌘ + D</ContextMenuShortcut> */}\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger>Turn into</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-48\">\n <ContextMenuItem onClick={() => handleTurnInto(KEYS.p)}>\n Paragraph\n </ContextMenuItem>\n\n <ContextMenuItem onClick={() => handleTurnInto(KEYS.h1)}>\n Heading 1\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleTurnInto(KEYS.h2)}>\n Heading 2\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleTurnInto(KEYS.h3)}>\n Heading 3\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => handleTurnInto(KEYS.blockquote)}\n >\n Blockquote\n </ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n </ContextMenuGroup>\n\n <ContextMenuGroup>\n <ContextMenuItem\n onClick={() =>\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setIndent(1)\n }\n >\n Indent\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() =>\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setIndent(-1)\n }\n >\n Outdent\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger>Align</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-48\">\n <ContextMenuItem onClick={() => handleAlign('left')}>\n Left\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleAlign('center')}>\n Center\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleAlign('right')}>\n Right\n </ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n </ContextMenuGroup>\n </ContextMenuContent>\n )}\n </ContextMenu>\n );\n}\n",
0 commit comments