瀏覽代碼

add focusNode custom hook

AykutSarac 3 年之前
父節點
當前提交
f573565348

+ 16 - 21
src/components/Input/index.tsx

@@ -1,8 +1,7 @@
 import React from "react";
 import { AiOutlineSearch } from "react-icons/ai";
 import { IoCloseSharp } from "react-icons/io5";
-import { useConfig } from "src/hocs/config";
-import { ConfigActionType } from "src/reducer/reducer";
+import { useFocusNode } from "src/hooks/useFocusNode";
 import styled from "styled-components";
 
 const StyledInputWrapper = styled.div`
@@ -48,32 +47,28 @@ const StyledSearchButton = styled.button`
   }
 `;
 
-export const Input = () => {
-  const { dispatch } = useConfig();
-  const [value, setValue] = React.useState("");
-
-  React.useEffect(() => {
-    const debouncer = setTimeout(() => {
-      dispatch({ type: ConfigActionType.SET_SEARCH_NODE, payload: value });
-    }, 1500);
-
-    return () => clearTimeout(debouncer);
-  }, [value, dispatch]);
-
-  const handleClick = () => {
-    setValue("");
-  };
+export const Input: React.FC = () => {
+  const [content, setContent] = useFocusNode();
 
   return (
     <StyledInputWrapper>
       <StyledInput
         type="text"
-        value={value}
-        onChange={(e) => setValue(e.target.value)}
+        value={content.value}
+        onChange={(e) =>
+          setContent((val) => ({ ...val, value: e.target.value }))
+        }
         placeholder="Search Node"
       />
-      <StyledSearchButton aria-label="search" onClick={handleClick}>
-        {value ? <IoCloseSharp size={18} /> : <AiOutlineSearch size={18} />}
+      <StyledSearchButton
+        aria-label="search"
+        onClick={() => setContent({ value: "", debounced: "" })}
+      >
+        {content.value ? (
+          <IoCloseSharp size={18} />
+        ) : (
+          <AiOutlineSearch size={18} />
+        )}
       </StyledSearchButton>
     </StyledInputWrapper>
   );

+ 0 - 1
src/constants/data.ts

@@ -38,7 +38,6 @@ export const defaultConfig: StorageConfig = {
   expand: true,
   autoformat: true,
   hideEditor: false,
-  searchNode: "",
   zoomPanPinch: null,
   lightmode: false
 };

+ 2 - 34
src/containers/LiveEditor/index.tsx

@@ -13,6 +13,7 @@ import { useLoading } from "src/hooks/useLoading";
 import { useConfig } from "src/hocs/config";
 import { Tools } from "../Editor/Tools";
 import { ConfigActionType } from "src/reducer/reducer";
+import { useFocusNode } from "src/hooks/useFocusNode";
 
 const StyledLiveEditor = styled.div`
   position: relative;
@@ -51,49 +52,16 @@ export const LiveEditor: React.FC = React.memo(function LiveEditor() {
     setData({ nodes, edges });
   }, [json, settings.expand]);
 
-  React.useEffect(() => {
-    if (!settings.zoomPanPinch) return;
-    const zoomPanPinch = settings.zoomPanPinch.instance.wrapperComponent;
-
-    const node = document.querySelector(
-      `span[data-key*='${settings.searchNode}' i]`
-    );
-
-    document
-      .querySelector("foreignObject.searched")
-      ?.classList.remove("searched");
-
-    if (zoomPanPinch && node && node.parentElement) {
-      const newScale = 1;
-      const x = Number(node.getAttribute("data-x"));
-      const y = Number(node.getAttribute("data-y"));
-
-      const newPositionX =
-        (zoomPanPinch.offsetLeft - x) * newScale +
-        node.getBoundingClientRect().width;
-      const newPositionY =
-        (zoomPanPinch.offsetTop - y) * newScale +
-        node.getBoundingClientRect().height;
-
-      node.parentElement.parentElement
-        ?.closest("foreignObject")
-        ?.classList.toggle("searched");
-
-      settings.zoomPanPinch?.setTransform(newPositionX, newPositionY, newScale);
-    }
-  }, [settings.searchNode, settings.zoomPanPinch]);
-
   const onCanvasClick = () => {
     const input = document.querySelector("input:focus") as HTMLInputElement;
     if (input) input.blur();
   };
 
-  const onInit = (ref: ReactZoomPanPinchRef) => {
+  const onInit = (ref: ReactZoomPanPinchRef) =>
     dispatch({
       type: ConfigActionType.SET_ZOOM_PAN_PICNH_REF,
       payload: ref,
     });
-  };
 
   if (pageLoaded)
     return (

+ 57 - 0
src/hooks/useFocusNode.tsx

@@ -0,0 +1,57 @@
+import React from "react";
+import { useConfig } from "src/hocs/config";
+
+type Content = { value: string; debounced: string };
+
+export const useFocusNode = () => {
+  const [content, setContent] = React.useState({
+    value: "",
+    debounced: "",
+  });
+
+  const {
+    states: { settings },
+  } = useConfig();
+
+  React.useEffect(() => {
+    const debouncer = setTimeout(() => {
+      setContent((val) => ({ ...val, debounced: content.value }));
+    }, 1500);
+
+    return () => clearTimeout(debouncer);
+  }, [content.value]);
+
+  React.useEffect(() => {
+    if (!settings.zoomPanPinch) return;
+    const zoomPanPinch = settings.zoomPanPinch.instance.wrapperComponent;
+
+    const node = document.querySelector(
+      `span[data-key*='${content.debounced}' i]`
+    );
+
+    document
+      .querySelector("foreignObject.searched")
+      ?.classList.remove("searched");
+
+    if (zoomPanPinch && node && node.parentElement) {
+      const newScale = 1;
+      const x = Number(node.getAttribute("data-x"));
+      const y = Number(node.getAttribute("data-y"));
+
+      const newPositionX =
+        (zoomPanPinch.offsetLeft - x) * newScale +
+        node.getBoundingClientRect().width;
+      const newPositionY =
+        (zoomPanPinch.offsetTop - y) * newScale +
+        node.getBoundingClientRect().height;
+
+      node.parentElement.parentElement
+        ?.closest("foreignObject")
+        ?.classList.toggle("searched");
+
+      settings.zoomPanPinch?.setTransform(newPositionX, newPositionY, newScale);
+    }
+  }, [content, settings.zoomPanPinch]);
+
+  return [content, setContent] as const;
+};

+ 0 - 10
src/reducer/reducer.ts

@@ -13,7 +13,6 @@ export enum ConfigActionType {
   ZOOM_OUT,
   CENTER_VIEW,
   SET_JSON,
-  SET_SEARCH_NODE,
   SET_ZOOM_PAN_PICNH_REF,
 }
 
@@ -51,15 +50,6 @@ export const useConfigReducer: React.Reducer<AppConfig, ReducerAction> = (
         },
       };
 
-    case ConfigActionType.SET_SEARCH_NODE:
-      return {
-        ...state,
-        settings: {
-          ...state.settings,
-          searchNode: action.payload,
-        },
-      };
-
     case ConfigActionType.CENTER_VIEW:
       state.settings.zoomPanPinch?.resetTransform();
       return state;

+ 0 - 1
src/typings/global.ts

@@ -7,7 +7,6 @@ export interface StorageConfig {
   expand: boolean;
   autoformat: boolean;
   hideEditor: boolean;
-  searchNode: string;
   zoomPanPinch: ReactZoomPanPinchRef | null;
   lightmode: boolean;
 }