key enter to trigger next result

This commit is contained in:
codetypes committed 2024-04-27 13:20:15 +08:00
1 parent 0cbbde3820
commit 5e6f177132
1 file changed
+106 -99
+106 -99
View File
@@ -8,6 +8,7 @@ import {
import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type"; import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type";
import * as b3util from "@/misc/b3util"; import * as b3util from "@/misc/b3util";
import { message } from "@/misc/hooks"; import { message } from "@/misc/hooks";
import i18n from "@/misc/i18n";
import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys"; import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys";
import Path from "@/misc/path"; import Path from "@/misc/path";
import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined } from "@ant-design/icons"; import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined } from "@ant-design/icons";
@@ -21,8 +22,7 @@ import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "re
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FiDelete } from "react-icons/fi"; import { FiDelete } from "react-icons/fi";
import { IoMdReturnLeft } from "react-icons/io"; import { IoMdReturnLeft } from "react-icons/io";
import { PiCubeFocus } from "react-icons/pi"; import { RiFocus3Line } from "react-icons/ri";
import { RiFocus3Fill, RiFocus3Line } from "react-icons/ri";
import { VscCaseSensitive } from "react-icons/vsc"; import { VscCaseSensitive } from "react-icons/vsc";
import { mergeRefs } from "react-merge-refs"; import { mergeRefs } from "react-merge-refs";
import { useDebounceCallback } from "usehooks-ts"; import { useDebounceCallback } from "usehooks-ts";
@@ -33,6 +33,86 @@ export interface EditorProps extends React.HTMLAttributes<HTMLElement> {
onUpdate: () => void; onUpdate: () => void;
} }
const createMenu = () => {
const t = i18n.t;
const MenuItem: FC<FlexProps> = (itemProps) => {
return (
<Flex
gap="50px"
style={{ minWidth: "200px", justifyContent: "space-between", alignItems: "center" }}
{...itemProps}
></Flex>
);
};
const arr: MenuProps["items"] = [
{
label: (
<MenuItem>
<div>{t("copy")}</div>
<div>{isMacos ? "⌘ C" : "Ctrl+C"}</div>
</MenuItem>
),
key: "copy",
},
{
label: (
<MenuItem>
<div>{t("paste")}</div>
<div>{isMacos ? "⌘ V" : "Ctrl+V"}</div>
</MenuItem>
),
key: "paste",
},
{
label: (
<MenuItem>
<div>{t("replace")}</div>
<div>{isMacos ? "⇧ ⌘ V" : "Ctrl+Shift+V"} </div>
</MenuItem>
),
key: "replace",
},
{
label: (
<MenuItem>
<div>{t("insertNode")}</div>
<div>{isMacos ? <IoMdReturnLeft /> : "Enter"}</div>
</MenuItem>
),
key: "insert",
},
{
label: (
<MenuItem>
<div>{t("deleteNode")}</div>
<div>{isMacos ? <FiDelete /> : "Backspace"}</div>
</MenuItem>
),
key: "delete",
},
{
label: (
<MenuItem>
<div>{t("editSubtree")}</div>
<div></div>
</MenuItem>
),
key: "editSubtree",
},
{
label: (
<MenuItem>
<div>{t("saveAsSubtree")}</div>
<div></div>
</MenuItem>
),
key: "saveAsSubtree",
},
];
return arr;
};
export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, ...props }) => { export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, ...props }) => {
const workspace = { const workspace = {
editing: useWorkspace((state) => state.editing), editing: useWorkspace((state) => state.editing),
@@ -48,6 +128,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
const sizeRef = useRef(null); const sizeRef = useRef(null);
const editorSize = useSize(sizeRef); const editorSize = useSize(sizeRef);
const { t } = useTranslation(); const { t } = useTranslation();
const menuItems = useMemo(() => createMenu(), [t]);
const onSearchChange = useDebounceCallback((filter: string) => { const onSearchChange = useDebounceCallback((filter: string) => {
const ids = filterNodes(filter, findDataById("1")); const ids = filterNodes(filter, findDataById("1"));
@@ -465,7 +546,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
message.warning(t("node.noNodeSelected")); message.warning(t("node.noNodeSelected"));
return; return;
} }
const d1 = findDataById(editor.selectedId);
const data = findSubtree(findDataById(editor.selectedId)); const data = findSubtree(findDataById(editor.selectedId));
if (data?.path) { if (data?.path) {
const path = `${workspace.workdir}/${data.path}`; const path = `${workspace.workdir}/${data.path}`;
@@ -901,85 +982,6 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
} }
}, [workspace.editing]); }, [workspace.editing]);
const menuItems = useMemo(() => {
const MenuItem: FC<FlexProps> = (itemProps) => {
return (
<Flex
gap="50px"
style={{ minWidth: "200px", justifyContent: "space-between", alignItems: "center" }}
{...itemProps}
></Flex>
);
};
const arr: MenuProps["items"] = [
{
label: (
<MenuItem>
<div>{t("copy")}</div>
<div>{isMacos ? "⌘ C" : "Ctrl+C"}</div>
</MenuItem>
),
key: "copy",
},
{
label: (
<MenuItem>
<div>{t("paste")}</div>
<div>{isMacos ? "⌘ V" : "Ctrl+V"}</div>
</MenuItem>
),
key: "paste",
},
{
label: (
<MenuItem>
<div>{t("replace")}</div>
<div>{isMacos ? "⇧ ⌘ V" : "Ctrl+Shift+V"} </div>
</MenuItem>
),
key: "replace",
},
{
label: (
<MenuItem>
<div>{t("insertNode")}</div>
<div>{isMacos ? <IoMdReturnLeft /> : "Enter"}</div>
</MenuItem>
),
key: "insert",
},
{
label: (
<MenuItem>
<div>{t("deleteNode")}</div>
<div>{isMacos ? <FiDelete /> : "Backspace"}</div>
</MenuItem>
),
key: "delete",
},
{
label: (
<MenuItem>
<div>{t("editSubtree")}</div>
<div></div>
</MenuItem>
),
key: "editSubtree",
},
{
label: (
<MenuItem>
<div>{t("saveAsSubtree")}</div>
<div></div>
</MenuItem>
),
key: "saveAsSubtree",
},
];
return arr;
}, [t]);
useEffect(() => { useEffect(() => {
if (editor.graph) { if (editor.graph) {
editor.graph.changeData(editor.data); editor.graph.changeData(editor.data);
@@ -993,6 +995,25 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
editor.dispatch(info.key as EditEvent); editor.dispatch(info.key as EditEvent);
}, []); }, []);
const nextResult = () => {
if (results.length > 0) {
const idx = (resultIndex + 1) % results.length;
setResultIndex(idx);
editor.graph.focusItem(results[idx]);
selectNode(results[idx]);
}
};
const prevResult = () => {
if (results.length > 0) {
const idx = (resultIndex + results.length - 1) % results.length;
setResultIndex(idx);
console.log(idx, results[idx]);
editor.graph.focusItem(results[idx]);
selectNode(results[idx]);
}
};
return ( return (
<div <div
{...props} {...props}
@@ -1031,6 +1052,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
paddingRight: "2px", paddingRight: "2px",
}} }}
onChange={(e) => onSearchChange(e.currentTarget.value)} onChange={(e) => onSearchChange(e.currentTarget.value)}
onKeyDown={(e) => e.code === Hotkey.Enter && nextResult()}
suffix={ suffix={
<Flex style={{ alignItems: "center" }}> <Flex style={{ alignItems: "center" }}>
<Button <Button
@@ -1057,14 +1079,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
size="small" size="small"
style={{ width: "30px" }} style={{ width: "30px" }}
disabled={results.length == 0} disabled={results.length == 0}
onClick={() => { onClick={nextResult}
if (results.length > 0) {
const idx = (resultIndex + 1) % results.length;
setResultIndex(idx);
editor.graph.focusItem(results[idx]);
selectNode(results[idx]);
}
}}
/> />
<Button <Button
icon={<ArrowUpOutlined />} icon={<ArrowUpOutlined />}
@@ -1072,15 +1087,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
size="small" size="small"
style={{ width: "30px" }} style={{ width: "30px" }}
disabled={results.length == 0} disabled={results.length == 0}
onClick={() => { onClick={prevResult}
if (results.length > 0) {
const idx = (resultIndex + results.length - 1) % results.length;
setResultIndex(idx);
console.log(idx, results[idx]);
editor.graph.focusItem(results[idx]);
selectNode(results[idx]);
}
}}
/> />
<Button <Button
icon={<CloseOutlined />} icon={<CloseOutlined />}