Explorar o código

feat: 添加历史记录等

liaojiaxing hai 5 meses
pai
achega
d973dd0445

+ 8 - 3
apps/designer/src/components/FindReplaceModal.tsx

@@ -23,6 +23,8 @@ export default forwardRef(function FindReplaceModal(
     onFindPrev,
     onReplace,
     onReplaceAll,
+    right = 0,
+    top = 0
   }: {
     current: number;
     count: number;
@@ -32,6 +34,8 @@ export default forwardRef(function FindReplaceModal(
     onFindPrev: () => void;
     onReplace: (searchText: string, replaceText: string) => void;
     onReplaceAll: (searchText: string, replaceText: string) => void;
+    right: number;
+    top: number;
   },
   ref: React.Ref<FindReplaceModalRef>
 ) {
@@ -41,7 +45,8 @@ export default forwardRef(function FindReplaceModal(
   const [replaceText, setReplaceText] = useState("");
 
   useImperativeHandle(ref, () => ({
-    open() {
+    open(active = 1) {
+      setActive(active);
       setOpen(true);
     },
   }));
@@ -108,9 +113,9 @@ export default forwardRef(function FindReplaceModal(
       onStart={(event, uiData) => onStart(event, uiData)}
     >
       <div
-        className="w-320px fixed right-30px top-110px bg-white rounded-md shadow-md z-100 p-10px"
+        className="w-320px fixed bg-white rounded-md shadow-md z-100 p-10px"
         ref={draggleRef}
-        style={{ display: open ? "block" : "none" }}
+        style={{ display: open ? "block" : "none", right, top }}
       >
         <div className="flex items-ctenter px-10px">
           <span

+ 64 - 0
apps/designer/src/components/HistoryPanel.tsx

@@ -0,0 +1,64 @@
+import { Button } from "antd";
+import React, { useState, forwardRef, useImperativeHandle } from "react";
+import { useModel } from "umi";
+
+export default forwardRef(function HistoryPanel(props, ref) {
+  const {
+    showHistory,
+    setShowHistory
+  } = useModel("appModel");
+
+
+  const ItemComponent = () => {
+    const [showBtn, setShowBtn] = useState(false);
+
+    return (
+      <div
+        className="flex items-center p-12px hover:bg-#f9f9f9"
+        onMouseOver={() => setShowBtn(true)}
+        onMouseOut={() => setShowBtn(false)}
+      >
+        <div className="flex-1">
+          <div className="text-sm text-#333">标题xxxxxxxxxxxxxx</div>
+          <div className="text-xs text-#999">2024-12-12 20:08:30</div>
+        </div>
+        {showBtn && (
+          <div>
+            <Button
+              type="text"
+              size="small"
+              icon={<i className="iconfont icon-lishijilu" />}
+            />
+            <Button
+              type="text"
+              size="small"
+              icon={<i className="iconfont icon-shanchu" />}
+            />
+          </div>
+        )}
+      </div>
+    );
+  };
+
+  return (
+    <div
+      className="absolute left-0 top-0 w-full h-full bg-white flex flex-col"
+      style={{ display: showHistory ? "flex" : "none" }}
+    >
+      <div className="flex py-8px px-12px items-center border-b-1px border-b-solid border-b-#eee">
+        <div className="flex-1">历史记录</div>
+        <div
+          className="w-16px h-16px cursor-pointer"
+          onClick={() => setShowHistory(false)}
+        >
+          <i className="iconfont icon-cuowu-1 color-#666 hover:color-#333" />
+        </div>
+      </div>
+      <div className="flex-1 overflow-y-auto">
+        {new Array(100).fill(0).map((_, i) => (
+          <ItemComponent key={i} />
+        ))}
+      </div>
+    </div>
+  );
+});

+ 76 - 2
apps/designer/src/components/mindMap/Text.tsx

@@ -1,4 +1,4 @@
-import React, { useMemo, useRef } from "react";
+import React, { useEffect, useMemo, useRef, useState } from "react";
 import { Input, InputRef } from "antd";
 import { Node } from "@antv/x6";
 import { useSafeState } from "ahooks";
@@ -49,6 +49,80 @@ export default function Text(props: {
     setIsEditing(edit);
   };
 
+  const [findObj, setFindObj] = useState<{
+    findStr: string;
+    currentCellId?: string;
+    currentIndex: number;
+  }>();
+  // 查找
+  const handleFind = (args: any) => {
+    setFindObj(args?.current || {});
+  };
+
+  const label = useMemo(() => {
+    if (!findObj) return value;
+    const list = (value || "").split(findObj.findStr || "");
+    return list.map((str: string, index) => {
+      // 当前的节点展示
+      const style =
+        findObj.currentCellId === node.id
+          ? {
+              background:
+                index + 1 === findObj.currentIndex
+                  ? "#FF9933"
+                  : "rgba(255, 153, 51, 0.25)",
+            }
+          : {
+              background: "#ffff00",
+            };
+      return (
+        <span key={index}>
+          {str}
+          {index < list.length - 1 && (
+            <span style={{
+              ...style,
+              color: '#333'
+            }}>{findObj.findStr}</span>
+          )}
+        </span>
+      );
+    });
+  }, [value, findObj]);
+
+  const handleReplace = (args: any) => {
+    const { type, searchText, replaceText, currentIndex, currentCellId } = args?.current || {};
+    if(args.current?.type === 'replaceAll') {
+      handleChange(value.replaceAll(searchText, replaceText));
+    }
+    if(type === 'replace' && currentCellId === node.id) {
+      const list = value.split(searchText);
+      const text = list.map((str, index) => {
+        const result = index + 1 === currentIndex ? replaceText : searchText;
+        return str + (index < list.length - 1 ? result : '');
+      }).join("");
+      handleChange(text);
+    }
+  };
+
+  const handleClear = () => {
+    setFindObj(undefined);
+  };
+
+  useEffect(() => {
+    node.off("change:find", handleFind);
+    node.off("change:replace", handleReplace);
+    node.off("change:clearFind", handleClear);
+
+    node.on("change:find", handleFind);
+    node.on("change:replace", handleReplace);
+    node.on("change:clearFind", handleClear);
+    return () => {
+      node.off("change:find", handleFind);
+      node.off("change:replace", handleReplace);
+      node.off("change:clearFind", handleClear);
+    };
+  }, [value]);
+
   // useEffect(() => {
   //   // 处理字体加载
   //   // @ts-ignore
@@ -68,7 +142,7 @@ export default function Text(props: {
         }}
         onDoubleClick={() => handleSetEditing(true)}
       >
-        {value}
+        {label}
       </div>
       {isEditing && (
         <Input.TextArea

+ 4 - 0
apps/designer/src/models/appModel.ts

@@ -43,6 +43,8 @@ export default function appModel() {
   const formatBrushStyle = useRef<cellStyle>();
   // 左侧面板激活
   const [leftPanelActiveKey, setLeftPanelActiveKey] = useState("1");
+  // 历史记录
+  const [showHistory, setShowHistory] = useState(false);
   // 右侧面板tab activeKey
   const [rightPanelTabActiveKey, setRightPanelTabActiveKey] = useState("1");
   const graphRef = useRef<Graph>();
@@ -179,5 +181,7 @@ export default function appModel() {
     setRightPanelTabActiveKey,
     leftPanelActiveKey,
     setLeftPanelActiveKey,
+    showHistory,
+    setShowHistory
   }
 }

+ 1 - 1
apps/designer/src/models/graphModel.ts

@@ -46,7 +46,7 @@ export default function GraphModel() {
   });
 
   const handleChangeAll = () => {
-    const cells = graph?.toJSON().cells || [];
+    const cells = (graph?.toJSON().cells || []).filter(cell => !cell?.data?.isPage);
 
     projectInfo &&
       setProjectInfo({

+ 1 - 0
apps/designer/src/pages/flow/components/Content/index.less

@@ -3,6 +3,7 @@
 .leftPanel {
   width: 224px;
   background: @background-color;
+  position: relative;
 }
 .designLayout {
   flex: 1;

+ 2 - 0
apps/designer/src/pages/flow/components/Content/index.tsx

@@ -10,6 +10,7 @@ import { BaseEdge } from '@/components/Edge';
 import { edgeMenu } from "@/utils/contentMenu";
 import StyleConfig from "./StyleConfig";
 import { ConnectorType } from "@/enum";
+import HistoryPanel from "@/components/HistoryPanel";
 export default function Content() {
   const stageRef = useRef<HTMLDivElement | null>(null);
   const { initGraph } = useModel("graphModel");
@@ -154,6 +155,7 @@ export default function Content() {
             },
           ]}
         />
+        <HistoryPanel />
       </div>
       <div className="w-12px drag-line"></div>
       <div

+ 0 - 1
apps/designer/src/pages/flow/components/Libary/index.tsx

@@ -1,5 +1,4 @@
 import React, {
-  useCallback,
   useEffect,
   useMemo,
   useRef,

+ 175 - 102
apps/designer/src/pages/flow/components/MenuBar/index.tsx

@@ -1,6 +1,6 @@
 import { DownloadOutlined, LeftOutlined } from "@ant-design/icons";
 import { Button, Input, Dropdown, MenuProps, Tooltip, InputRef } from "antd";
-import React, { useRef, useState } from "react";
+import React, { useEffect, useRef, useState } from "react";
 import logo from "@/assets/logo.png";
 import { Icon, useModel } from "umi";
 import { exportImage } from "@/components/ExportImage";
@@ -23,14 +23,16 @@ import {
   handleLock,
   handleUnLock,
   handleDelete,
-  createNew
+  createNew,
 } from "@/utils";
+import FindReplaceModal from "@/components/FindReplaceModal";
+import { useFindReplace } from "@/hooks/useFindReplace";
 
 InsertCss(`
   .custom-color-picker-popover {
   z-index: 9999;
 }
-  `)
+  `);
 export default function MenuBar() {
   const {
     projectInfo,
@@ -41,6 +43,7 @@ export default function MenuBar() {
     pageState,
     onChangePageSettings,
     setLeftPanelActiveKey,
+    setShowHistory,
   } = useModel("appModel");
   const { graph, canRedo, canUndo, selectedCell } = useModel("graphModel");
   const inputRef = useRef<InputRef>(null);
@@ -48,9 +51,56 @@ export default function MenuBar() {
   // 重命名
   const handleRename = () => {
     inputRef.current?.select();
-    inputRef.current?.setSelectionRange(0, projectInfo.name.length);
+    projectInfo &&
+      inputRef.current?.setSelectionRange(0, projectInfo.name.length);
   };
 
+  useEffect(() => {
+    if (projectInfo?.name !== name) {
+      setName(projectInfo?.name);
+    }
+  }, [projectInfo]);
+
+  // 修改项目名称
+  const handleChangeName = () => {
+    if (!name?.trim()) {
+      setName(projectInfo?.name);
+      return;
+    }
+    projectInfo &&
+      setProjectInfo({
+        ...projectInfo,
+        name: name,
+      });
+  };
+
+  const [name, setName] = useState(projectInfo?.name);
+
+  useEffect(() => {
+    setName(projectInfo?.name);
+  }, [projectInfo?.name]);
+
+  const {
+    handleFind,
+    handleReplace,
+    handleReplaceAll,
+    handleClose,
+    handleFindNext,
+    handleFindPrev,
+    findCount,
+    currentIndex,
+    setInstance,
+  } = useFindReplace(graph);
+
+  useEffect(() => {
+    graph && setInstance(graph);
+    setSelectionStrict(!!graph?.isStrictRubberband())
+  }, [graph]);
+
+  const findModalRef = useRef<any>();
+
+  const [selectionStrict, setSelectionStrict] = useState(true);
+
   // 预览 todo
   const handlePreview = () => {};
 
@@ -61,17 +111,13 @@ export default function MenuBar() {
   const handleClone = () => {};
 
   // 历史记录 todo
-  const handleHistory = () => {};
+  const handleHistory = () => {
+    setShowHistory(true);
+  };
 
   // 默认样式 todo
   const handleDefaultStyle = () => {};
 
-  // 查找 todo
-  const handleFind = () => {};
-
-  // 替换 todo
-  const handleReplace = () => {};
-
   // 数据属性 todo
   const handleShowDataAttr = () => {};
 
@@ -340,7 +386,9 @@ export default function MenuBar() {
             </div>
           ),
           icon: <i className="w-20px iconfont " />,
-          onClick: handleFind,
+          onClick: () => {
+            findModalRef.current?.open();
+          },
         },
         {
           key: "2-10",
@@ -351,7 +399,9 @@ export default function MenuBar() {
             </div>
           ),
           icon: <i className="w-20px iconfont " />,
-          onClick: handleReplace,
+          onClick: () => {
+            findModalRef.current?.open(2);
+          },
         },
         {
           key: "2-11",
@@ -385,7 +435,7 @@ export default function MenuBar() {
             </div>
           ),
           icon: <i className="w-20px iconfont " />,
-          onClick: () => selectAll,
+          onClick: () => graph && selectAll(graph),
         },
         {
           key: "3-2",
@@ -394,12 +444,20 @@ export default function MenuBar() {
         {
           key: "3-3",
           label: "框选部分选中数据",
-          icon: <i className="w-20px iconfont " />,
+          icon: <i className={`w-20px iconfont ${!selectionStrict ? "icon-cheked_16x16" : ''}`} />,
+          onClick: () => {
+            graph?.disableStrictRubberband();
+            setSelectionStrict(false);
+          }
         },
         {
           key: "3-4",
           label: "框选全部选中图形",
-          icon: <i className="w-20px iconfont " />,
+          icon: <i className={`w-20px iconfont ${selectionStrict ? "icon-cheked_16x16" : ''}`} />,
+          onClick: () => {
+            graph?.enableStrictRubberband();
+            setSelectionStrict(true);
+          }
         },
       ],
     },
@@ -527,16 +585,16 @@ export default function MenuBar() {
           ),
           onClick: () => graph && handleCreateEdge(graph),
         },
-        {
-          key: "5-5",
-          type: "divider",
-        },
-        {
-          key: "5-6",
-          label: "数据属性",
-          icon: <i className="w-20px iconfont icon-tubiao" />,
-          onClick: handleShowDataAttr,
-        },
+        // {
+        //   key: "5-5",
+        //   type: "divider",
+        // },
+        // {
+        //   key: "5-6",
+        //   label: "数据属性",
+        //   icon: <i className="w-20px iconfont icon-tubiao" />,
+        //   onClick: handleShowDataAttr,
+        // },
         // {
         //   key: "5-7",
         //   label: (
@@ -567,7 +625,7 @@ export default function MenuBar() {
             <CustomColorPicker
               otherPopoverAttr={{
                 placement: "left",
-                overlayClassName: "custom-color-picker-popover"
+                overlayClassName: "custom-color-picker-popover",
               }}
               color={pageState.backgroundColor}
               onChange={(color) =>
@@ -894,84 +952,99 @@ export default function MenuBar() {
   ];
 
   return (
-    <div className="w-full px-8px flex justify-between items-center">
-      <div className="menu-left flex items-center">
-        <Button type="text" icon={<LeftOutlined />}></Button>
-        <div className="w-40px h-40px mx-8px">
-          <img className="w-40px" src={logo} />
-        </div>
-        <div className="flex flex-col leading-32px">
-          <div>
-            <Input
-              ref={inputRef}
-              className="text-16px max-w-200px"
-              variant="borderless"
-              value={projectInfo.name}
-              onChange={(e) =>
-                setProjectInfo((state) => ({ ...state, name: e.target.value }))
-              }
-            />
+    <>
+      <div className="w-full px-8px flex justify-between items-center">
+        <div className="menu-left flex items-center">
+          <Button type="text" icon={<LeftOutlined />}></Button>
+          <div className="w-40px h-40px mx-8px">
+            <img className="w-40px" src={logo} />
           </div>
-          <div>
-            {menuData.map((item) => {
-              return (
-                <Dropdown
-                  key={item.key}
-                  menu={{ items: item.children, style: { width: 200 } }}
-                  placement="bottomLeft"
-                >
-                  <Button type="text" size="small">
-                    {item.label}
-                  </Button>
-                </Dropdown>
-              );
-            })}
+          <div className="flex flex-col leading-32px">
+            <div>
+              <Input
+                ref={inputRef}
+                className="text-16px max-w-200px"
+                variant="borderless"
+                value={name}
+                onChange={(e) => setName(e.target.value)}
+                onBlur={handleChangeName}
+                onPressEnter={handleChangeName}
+              />
+            </div>
+            <div>
+              {menuData.map((item) => {
+                return (
+                  <Dropdown
+                    key={item.key}
+                    menu={{ items: item.children, style: { width: 200 } }}
+                    placement="bottomLeft"
+                  >
+                    <Button type="text" size="small">
+                      {item.label}
+                    </Button>
+                  </Dropdown>
+                );
+              })}
+            </div>
           </div>
         </div>
+        <div>
+          <Dropdown
+            trigger={["click"]}
+            menu={{
+              items: [
+                {
+                  key: 1,
+                  label: (
+                    <span>
+                      <i className="w-20px iconfont icon-file-image" />
+                      PNG
+                    </span>
+                  ),
+                  onClick: () => graph && exportImage(graph, "png"),
+                },
+                {
+                  key: 2,
+                  label: (
+                    <span>
+                      <i className="w-20px iconfont icon-file-image" />
+                      JPG
+                    </span>
+                  ),
+                  onClick: () => graph && exportImage(graph, "jpg"),
+                },
+                {
+                  key: 3,
+                  label: (
+                    <span>
+                      <i className="w-20px iconfont icon-file-image" />
+                      SVG
+                    </span>
+                  ),
+                  onClick: () => graph && exportImage(graph, "svg"),
+                },
+              ],
+            }}
+          >
+            <Tooltip title="导出为">
+              <Button type="text" icon={<DownloadOutlined />}></Button>
+            </Tooltip>
+          </Dropdown>
+        </div>
       </div>
-      <div>
-        <Dropdown
-          trigger={["click"]}
-          menu={{
-            items: [
-              {
-                key: 1,
-                label: (
-                  <span>
-                    <i className="w-20px iconfont icon-file-image" />
-                    PNG
-                  </span>
-                ),
-                onClick: () => graph && exportImage(graph, "png"),
-              },
-              {
-                key: 2,
-                label: (
-                  <span>
-                    <i className="w-20px iconfont icon-file-image" />
-                    JPG
-                  </span>
-                ),
-                onClick: () => graph && exportImage(graph, "jpg"),
-              },
-              {
-                key: 3,
-                label: (
-                  <span>
-                    <i className="w-20px iconfont icon-file-image" />
-                    SVG
-                  </span>
-                ),
-                onClick: () => graph && exportImage(graph, "svg"),
-              },
-            ],
-          }}
-        >
-          <Tooltip title="导出为">
-            <Button type="text" icon={<DownloadOutlined />}></Button>
-          </Tooltip>
-        </Dropdown>
-      </div>
-    </div>
+      <FindReplaceModal
+        ref={findModalRef}
+        current={currentIndex}
+        count={findCount}
+        onClose={handleClose}
+        onFind={handleFind}
+        onFindNext={handleFindNext}
+        onFindPrev={handleFindPrev}
+        onReplace={handleReplace}
+        onReplaceAll={handleReplaceAll}
+        right={30}
+        top={110}
+      />
+    </>
   );
 }

+ 2 - 0
apps/designer/src/pages/flow/components/ToolBar/index.tsx

@@ -695,6 +695,8 @@ export default function ToolBar() {
           onFindPrev={handleFindPrev}
           onReplace={handleReplace}
           onReplaceAll={handleReplaceAll}
+          right={30}
+          top={110}
         />
         <div>
           <Tooltip placement="bottom" title="替换">

+ 58 - 27
apps/designer/src/pages/mindmap/components/HeaderToolbar/index.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from "react";
+import React, { useEffect, useMemo, useRef, useState } from "react";
 import { Button, Input, Dropdown, Tooltip, MenuProps, Divider } from "antd";
 import { LeftOutlined, MenuOutlined } from "@ant-design/icons";
 import logo from "@/assets/logo.png";
@@ -7,6 +7,8 @@ import { addTopic } from "../../mindMap";
 import { TopicType } from "@/enum";
 import { selectTopic, addBorder, addSummary } from "@/utils/mindmapHander";
 import { createNew } from "@/utils";
+import FindReplaceModal from "@/components/FindReplaceModal";
+import { useFindReplace } from "@/hooks/useFindReplace";
 
 export default function index() {
   const {
@@ -23,22 +25,35 @@ export default function index() {
     setCorrelationEdgeInfo,
   } = useModel("mindMapModel");
 
+  const {
+    handleFind,
+    handleReplace,
+    handleReplaceAll,
+    handleClose,
+    handleFindNext,
+    handleFindPrev,
+    findCount,
+    currentIndex,
+    setInstance,
+  } = useFindReplace(graph);
+
   const currentNode = useMemo(() => {
-    return selectedCell.filter(cell => cell.isNode());
+    return selectedCell.filter((cell) => cell.isNode());
   }, [selectedCell]);
 
   const [title, setTitle] = useState<string>(mindProjectInfo?.name || "");
 
   useEffect(() => {
     setTitle(mindProjectInfo?.name || "");
-  }, [mindProjectInfo?.name])
+  }, [mindProjectInfo?.name]);
 
   const handleChangeTitle = () => {
-    mindProjectInfo && setMindProjectInfo({
-      ...mindProjectInfo,
-      name: title,
-    })
-  }
+    mindProjectInfo &&
+      setMindProjectInfo({
+        ...mindProjectInfo,
+        name: title,
+      });
+  };
   // 预览 todo
   const handlePreview = () => {};
 
@@ -51,15 +66,20 @@ export default function index() {
   // 历史记录 todo
   const handleHistory = () => {};
 
-  // 查找替换
-  const handleReplace = () => {};
+  useEffect(() => {
+    graph && setInstance(graph);
+  }, [graph]);
+
+  const findModalRef = useRef<any>();
 
   // 增加子主题
   const handleAddSubTopic = () => {
-    if(!currentNode.length) return;
+    if (!currentNode.length) return;
 
     const topic = addTopic(
-      currentNode[0].data.type === TopicType.main ? TopicType.branch : TopicType.sub,
+      currentNode[0].data.type === TopicType.main
+        ? TopicType.branch
+        : TopicType.sub,
       setMindProjectInfo,
       currentNode[0]
     );
@@ -69,17 +89,17 @@ export default function index() {
 
   // 添加边框
   const handleAddBorder = () => {
-    addBorder(currentNode.filter(item => item.data.parentId));
-  }
+    addBorder(currentNode.filter((item) => item.data.parentId));
+  };
 
   // 添加概要
   const handleAddSummary = () => {
-    addSummary(currentNode.filter(item => item.data.parentId))
-  }
+    addSummary(currentNode.filter((item) => item.data.parentId));
+  };
 
   // 添加关联线
   const handleAddCorrelation = () => {
-    if(!currentNode.length) return;
+    if (!currentNode.length) return;
 
     setCorrelationEdgeInfo(currentNode[0]);
   };
@@ -167,7 +187,9 @@ export default function index() {
       key: "5",
       label: "查找替换",
       icon: <i className="w-20px iconfont icon-lishijilu" />,
-      onClick: handleReplace,
+      onClick: () => {
+        findModalRef.current?.open();
+      },
     },
     {
       key: "6",
@@ -182,9 +204,8 @@ export default function index() {
   ];
 
   const noParent = useMemo(() => {
-    const nodes = selectedCell?.filter(cell => cell.isNode());
-    return !!(nodes.length && !nodes.find(node => !node.data?.parentId));
-
+    const nodes = selectedCell?.filter((cell) => cell.isNode());
+    return !!(nodes.length && !nodes.find((node) => !node.data?.parentId));
   }, [selectedCell]);
 
   return (
@@ -207,9 +228,7 @@ export default function index() {
             className="text-16px max-w-100px"
             variant="borderless"
             value={title}
-            onChange={(e) =>
-              setTitle(e.target.value)
-            }
+            onChange={(e) => setTitle(e.target.value)}
             onBlur={handleChangeTitle}
             onPressEnter={handleChangeTitle}
           />
@@ -242,9 +261,7 @@ export default function index() {
           type="text"
           icon={<i className="iconfont icon-geshishua"></i>}
           disabled={!currentNode?.length}
-          className={
-            enableFormatBrush && currentNode?.length ? "active" : ""
-          }
+          className={enableFormatBrush && currentNode?.length ? "active" : ""}
           onClick={() => graph && toggleFormatBrush(graph)}
         />
       </Tooltip>
@@ -286,6 +303,20 @@ export default function index() {
           onClick={handleAddBorder}
         />
       </Tooltip>
+
+      <FindReplaceModal
+        ref={findModalRef}
+        current={currentIndex}
+        count={findCount}
+        onClose={handleClose}
+        onFind={handleFind}
+        onFindNext={handleFindNext}
+        onFindPrev={handleFindPrev}
+        onReplace={handleReplace}
+        onReplaceAll={handleReplaceAll}
+        right={80}
+        top={10}
+      />
     </div>
   );
 }