返回 presentation-ai
text-to-diagram-toolbar-button.tsx
根目录 / src / components / plate / ui / text-to-diagram-toolbar-button.tsx
1 "use client";
2
3 import { MarkdownPlugin } from "@platejs/markdown";
4 import { BlockSelectionPlugin } from "@platejs/selection/react";
5 import { ZapIcon } from "lucide-react";
6 import { nanoid } from "platejs";
7 import { useEditorRef } from "platejs/react";
8 import { useCallback } from "react";
9
10 import { ANTV_INFOGRAPHIC } from "@/components/notebook/presentation/editor/lib";
11 import { type TAntvInfographicElement } from "@/components/notebook/presentation/editor/plugins/antv-infographic-plugin";
12 import { ToolbarButton } from "./toolbar";
13
14 export function TextToDiagramToolbarButton() {
15 const editor = useEditorRef();
16
17 const handleClick = useCallback(() => {
18 // Try to get text from block selection first
19 const blockSelectionApi =
20 editor.getApi(BlockSelectionPlugin)?.blockSelection;
21 const selectedBlocks = blockSelectionApi
22 ? blockSelectionApi.getNodes()
23 : [];
24 const markdownApi = editor.getApi(MarkdownPlugin).markdown;
25
26 let selectedText = "";
27
28 if (selectedBlocks.length > 0) {
29 selectedText = markdownApi.serialize({
30 value: selectedBlocks.map(([node]) => node),
31 withBlockId: true,
32 });
33 } else if (editor.selection) {
34 selectedText = editor.api.string(editor.selection);
35
36 if (!selectedText.trim()) {
37 const block = editor.api.block({ at: editor.selection });
38
39 if (block) {
40 selectedText = markdownApi.serialize({
41 value: [block[0]],
42 withBlockId: true,
43 });
44 }
45 }
46 }
47
48 if (!selectedText || selectedText.trim().length === 0) {
49 return;
50 }
51
52 // Create the infographic element in loading state
53 const infographicElement: TAntvInfographicElement = {
54 type: ANTV_INFOGRAPHIC,
55 id: nanoid(),
56 syntax: "",
57 isLoading: true,
58 sourceText: selectedText,
59 width: "100%",
60 align: "center",
61 children: [{ text: "" }],
62 };
63
64 if (selectedBlocks.length > 0) {
65 // Insert after the last selected block
66 const lastBlockPath = selectedBlocks[selectedBlocks.length - 1]![1];
67 const insertPath = [lastBlockPath[0]! + 1];
68 editor.tf.insertNodes(infographicElement, {
69 at: insertPath,
70 });
71
72 // Clear the block selection after insertion
73 editor.getApi(BlockSelectionPlugin)?.blockSelection.unselect();
74 } else if (editor.selection) {
75 // Insert after the current block
76 const entry = editor.api.block();
77 if (entry) {
78 const [, path] = entry;
79 editor.tf.insertNodes(infographicElement, {
80 at: [path[0]! + 1],
81 });
82 } else {
83 // Fallback: insert at selection
84 editor.tf.insertNodes(infographicElement);
85 }
86 } else {
87 // Insert at the end if no selection
88 editor.tf.insertNodes(infographicElement);
89 }
90 }, [editor]);
91
92 return (
93 <ToolbarButton tooltip="Text to Diagram" onClick={handleClick}>
94 <ZapIcon />
95 </ToolbarButton>
96 );
97 }
98
98 lines Plain Text