From f5735653482ed19b59a81b64bb44d5925580d7ca Mon Sep 17 00:00:00 2001 From: AykutSarac Date: Sun, 24 Apr 2022 23:27:14 +0300 Subject: [PATCH] add focusNode custom hook --- src/components/Input/index.tsx | 37 ++++++++----------- src/constants/data.ts | 1 - src/containers/LiveEditor/index.tsx | 36 +----------------- src/hooks/useFocusNode.tsx | 57 +++++++++++++++++++++++++++++ src/reducer/reducer.ts | 10 ----- src/typings/global.ts | 1 - 6 files changed, 75 insertions(+), 67 deletions(-) create mode 100644 src/hooks/useFocusNode.tsx diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index dfe1774..2af2c72 100644 --- a/src/components/Input/index.tsx +++ b/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 ( setValue(e.target.value)} + value={content.value} + onChange={(e) => + setContent((val) => ({ ...val, value: e.target.value })) + } placeholder="Search Node" /> - - {value ? : } + setContent({ value: "", debounced: "" })} + > + {content.value ? ( + + ) : ( + + )} ); diff --git a/src/constants/data.ts b/src/constants/data.ts index bc36301..acbf057 100644 --- a/src/constants/data.ts +++ b/src/constants/data.ts @@ -38,7 +38,6 @@ export const defaultConfig: StorageConfig = { expand: true, autoformat: true, hideEditor: false, - searchNode: "", zoomPanPinch: null, lightmode: false }; diff --git a/src/containers/LiveEditor/index.tsx b/src/containers/LiveEditor/index.tsx index 947ec84..047e78f 100644 --- a/src/containers/LiveEditor/index.tsx +++ b/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 ( diff --git a/src/hooks/useFocusNode.tsx b/src/hooks/useFocusNode.tsx new file mode 100644 index 0000000..0d9f0d0 --- /dev/null +++ b/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; +}; diff --git a/src/reducer/reducer.ts b/src/reducer/reducer.ts index bb1a665..5618cce 100644 --- a/src/reducer/reducer.ts +++ b/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 = ( }, }; - case ConfigActionType.SET_SEARCH_NODE: - return { - ...state, - settings: { - ...state.settings, - searchNode: action.payload, - }, - }; - case ConfigActionType.CENTER_VIEW: state.settings.zoomPanPinch?.resetTransform(); return state; diff --git a/src/typings/global.ts b/src/typings/global.ts index 3bce009..ca1e51e 100644 --- a/src/typings/global.ts +++ b/src/typings/global.ts @@ -7,7 +7,6 @@ export interface StorageConfig { expand: boolean; autoformat: boolean; hideEditor: boolean; - searchNode: string; zoomPanPinch: ReactZoomPanPinchRef | null; lightmode: boolean; }