AykutSarac 2 years ago
parent
commit
be07f7b783
51 changed files with 368 additions and 344 deletions
  1. 1 4
      .eslintrc.json
  2. 3 1
      .prettierignore
  3. 13 3
      .prettierrc
  4. 0 1
      jest.setup.ts
  5. 2 0
      package.json
  6. 2 4
      src/components/CarbonAds/index.tsx
  7. 4 12
      src/components/CustomNode/ObjectNode.tsx
  8. 6 13
      src/components/CustomNode/TextNode.tsx
  9. 5 5
      src/components/CustomNode/styles.tsx
  10. 2 6
      src/components/ErrorContainer/index.tsx
  11. 1 1
      src/components/GoogleAnalytics/index.tsx
  12. 10 18
      src/components/Graph/index.tsx
  13. 1 3
      src/components/Input/index.tsx
  14. 3 3
      src/components/Modal/index.tsx
  15. 8 10
      src/components/MonacoEditor/index.tsx
  16. 2 8
      src/components/SearchInput/index.tsx
  17. 1 5
      src/components/SeoTags/index.tsx
  18. 15 19
      src/components/Sidebar/index.tsx
  19. 2 2
      src/components/Sponsors/index.tsx
  20. 2 6
      src/components/Toggle/index.tsx
  21. 2 2
      src/components/Tooltip/index.tsx
  22. 2 4
      src/components/__tests__/Button.test.tsx
  23. 1 5
      src/constants/data.ts
  24. 1 1
      src/containers/Editor/JsonEditor/index.tsx
  25. 9 11
      src/containers/Editor/LiveEditor/GraphCanvas.tsx
  26. 2 2
      src/containers/Editor/LiveEditor/index.tsx
  27. 6 9
      src/containers/Editor/Panes.tsx
  28. 11 21
      src/containers/Editor/Tools.tsx
  29. 18 23
      src/containers/Home/index.tsx
  30. 1 1
      src/containers/Home/styles.tsx
  31. 1 1
      src/containers/Modals/ClearModal/index.tsx
  32. 13 22
      src/containers/Modals/DownloadModal/index.tsx
  33. 3 3
      src/containers/Modals/GoalsModal/index.tsx
  34. 7 8
      src/containers/Modals/ImportModal/index.tsx
  35. 1 5
      src/containers/Modals/NodeModal/index.tsx
  36. 3 3
      src/containers/Modals/SettingsModal/index.tsx
  37. 11 17
      src/containers/Modals/ShareModal/index.tsx
  38. 3 4
      src/hooks/store/useConfig.tsx
  39. 14 10
      src/hooks/store/useGraph.tsx
  40. 2 2
      src/hooks/store/useStored.tsx
  41. 4 5
      src/hooks/useFocusNode.tsx
  42. 1 2
      src/pages/404.tsx
  43. 2 2
      src/pages/Editor/index.tsx
  44. 6 7
      src/pages/Widget/index.tsx
  45. 9 24
      src/pages/_app.tsx
  46. 2 5
      src/pages/_document.tsx
  47. 3 4
      src/utils/getChildrenEdges.ts
  48. 5 4
      src/utils/getOutgoers.ts
  49. 5 9
      src/utils/jsonParser.ts
  50. 2 2
      src/utils/search.ts
  51. 135 2
      yarn.lock

+ 1 - 4
.eslintrc.json

@@ -7,10 +7,7 @@
   "overrides": [
     // Only uses Testing Library lint rules in test files
     {
-      "files": [
-        "**/__tests__/**/*.[jt]s?(x)",
-        "**/?(*.)+(spec|test).[jt]s?(x)"
-      ],
+      "files": ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"],
       "extends": ["plugin:testing-library/react"]
     }
   ]

+ 3 - 1
.prettierignore

@@ -2,4 +2,6 @@
 .next
 node_modules/
 out
-public
+public
+*-lock.json
+tsconfig.json

+ 13 - 3
.prettierrc

@@ -2,8 +2,18 @@
   "trailingComma": "es5",
   "singleQuote": false,
   "semi": true,
-  "printWidth": 80,
-  "importOrder": ["^[~]", "^[./]"],
-  "importOrderSortSpecifiers": true,
+  "printWidth": 85,
+  "arrowParens": "avoid",
+  "importOrder": [
+    "^(react/(.*)$)|^(react$)",
+    "^(next/(.*)$)|^(next$)",
+    "<THIRD_PARTY_MODULES>",
+    "next-seo.config",
+    "^components/(.*)$",
+    "^utils/(.*)$",
+    "^assets/(.*)$",
+    "^@fontsource/(.*)$",
+    "^[./]"
+  ],
   "importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"]
 }

+ 0 - 1
jest.setup.ts

@@ -1,6 +1,5 @@
 // Optional: configure or set up a testing framework before each test.
 // If you delete this file, remove `setupFilesAfterEnv` from `jest.config.js`
-
 // Used for __tests__/testing-library.js
 // Learn more: https://github.com/testing-library/jest-dom
 import "@testing-library/jest-dom/extend-expect";

+ 2 - 0
package.json

@@ -10,6 +10,7 @@
     "test": "jest",
     "start": "next start",
     "lint": "next lint",
+    "lint:fix": "prettier --write \"./**/*.{ts,tsx,json}\"",
     "deploy": "gh-pages -d out -t true"
   },
   "dependencies": {
@@ -38,6 +39,7 @@
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.3.0",
     "@testing-library/user-event": "^14.4.3",
+    "@trivago/prettier-plugin-sort-imports": "^3.3.0",
     "@types/enzyme": "^3.10.12",
     "@types/jest": "^29.0.0",
     "@types/node": "^18.7.14",

+ 2 - 4
src/components/CarbonAds/index.tsx

@@ -1,5 +1,5 @@
-import Script from "next/script";
 import React from "react";
+import Script from "next/script";
 import { IoMdClose } from "react-icons/io";
 import styled from "styled-components";
 
@@ -52,9 +52,7 @@ const StyledWrapper = styled.span<{ editor?: boolean }>`
   }
 `;
 
-export const CarbonAds: React.FC<{ editor?: boolean }> = ({
-  editor = false,
-}) => {
+export const CarbonAds: React.FC<{ editor?: boolean }> = ({ editor = false }) => {
   const [isHidden, setIsHidden] = React.useState(false);
 
   if (isHidden) return null;

+ 4 - 12
src/components/CustomNode/ObjectNode.tsx

@@ -1,23 +1,17 @@
 import React from "react";
+import { useInViewport } from "react-in-viewport";
 import { CustomNodeProps } from "src/components/CustomNode";
 import useConfig from "src/hooks/store/useConfig";
-import { useInViewport } from "react-in-viewport";
 import * as Styled from "./styles";
 
 const inViewport = true;
 
 type ObjectNodeProps = CustomNodeProps<[string, string][]>;
 
-const ObjectNode: React.FC<ObjectNodeProps> = ({
-  width,
-  height,
-  value,
-  x,
-  y,
-}) => {
+const ObjectNode: React.FC<ObjectNodeProps> = ({ width, height, value, x, y }) => {
   const ref = React.useRef(null);
   // const { inViewport } = useInViewport(ref);
-  const performanceMode = useConfig((state) => state.performanceMode);
+  const performanceMode = useConfig(state => state.performanceMode);
 
   return (
     <Styled.StyledForeignObject
@@ -39,9 +33,7 @@ const ObjectNode: React.FC<ObjectNodeProps> = ({
             <Styled.StyledKey objectKey>
               {JSON.stringify(val[0]).replaceAll('"', "")}:{" "}
             </Styled.StyledKey>
-            <Styled.StyledLinkItUrl>
-              {JSON.stringify(val[1])}
-            </Styled.StyledLinkItUrl>
+            <Styled.StyledLinkItUrl>{JSON.stringify(val[1])}</Styled.StyledLinkItUrl>
           </Styled.StyledRow>
         ))}
     </Styled.StyledForeignObject>

+ 6 - 13
src/components/CustomNode/TextNode.tsx

@@ -52,18 +52,15 @@ const TextNode: React.FC<TextNodeProps> = ({
 }) => {
   const ref = React.useRef(null);
   // const { inViewport } = useInViewport(ref);
-  const performanceMode = useConfig((state) => state.performanceMode);
+  const performanceMode = useConfig(state => state.performanceMode);
 
-  const hideCollapse = useStored((state) => state.hideCollapse);
-  const expandNodes = useGraph((state) => state.expandNodes);
-  const collapseNodes = useGraph((state) => state.collapseNodes);
-  const isExpanded = useGraph((state) =>
-    state.collapsedParents.includes(node.id)
-  );
+  const hideCollapse = useStored(state => state.hideCollapse);
+  const expandNodes = useGraph(state => state.expandNodes);
+  const collapseNodes = useGraph(state => state.collapseNodes);
+  const isExpanded = useGraph(state => state.collapsedParents.includes(node.id));
 
   const handleExpand = (e: React.MouseEvent<HTMLButtonElement>) => {
     e.stopPropagation();
-    // setIsExpanded(!isExpanded);
 
     if (!isExpanded) collapseNodes(node.id);
     else expandNodes(node.id);
@@ -96,11 +93,7 @@ const TextNode: React.FC<TextNodeProps> = ({
 
         {inViewport && isParent && hasCollapse && !hideCollapse && (
           <StyledExpand onClick={handleExpand}>
-            {isExpanded ? (
-              <MdLinkOff size={18} />
-            ) : (
-              <MdLink size={18} />
-            )}
+            {isExpanded ? <MdLinkOff size={18} /> : <MdLink size={18} />}
           </StyledExpand>
         )}
       </StyledTextNodeWrapper>

+ 5 - 5
src/components/CustomNode/styles.tsx

@@ -1,5 +1,5 @@
-import styled, { DefaultTheme } from "styled-components";
 import { LinkItUrl } from "react-linkify-it";
+import styled, { DefaultTheme } from "styled-components";
 
 function getTypeColor(value: string, theme: DefaultTheme) {
   if (!Number.isNaN(+value)) return "#FD0079";
@@ -34,7 +34,7 @@ export const StyledForeignObject = styled.foreignObject<{
   }
 
   .highlight {
-    border: 2px dashed #FF2970;
+    border: 2px dashed #ff2970;
     background: rgba(255, 214, 0, 0.3);
   }
 
@@ -73,13 +73,13 @@ export const StyledKey = styled.span<{
 `;
 
 export const StyledRow = styled.span.attrs<{
-  'data-key': string;
+  "data-key": string;
   theme: DefaultTheme;
-}>((props) => ({
+}>(props => ({
   style: {
     color: getTypeColor(props["data-key"], props.theme),
   },
-}))<{ 'data-key': string; theme: DefaultTheme }>`
+}))<{ "data-key": string; theme: DefaultTheme }>`
   display: block;
   height: 18px;
   overflow: hidden;

+ 2 - 6
src/components/ErrorContainer/index.tsx

@@ -1,9 +1,6 @@
 import React from "react";
+import { MdReportGmailerrorred, MdOutlineCheckCircleOutline } from "react-icons/md";
 import styled from "styled-components";
-import {
-  MdReportGmailerrorred,
-  MdOutlineCheckCircleOutline,
-} from "react-icons/md";
 
 const StyledErrorWrapper = styled.div`
   z-index: 1;
@@ -18,8 +15,7 @@ const StyledErrorExpand = styled.div<{ error: boolean }>`
   border-radius: 0;
   justify-content: space-between;
   align-items: center;
-  color: ${({ theme, error }) =>
-    error ? theme.TEXT_DANGER : theme.TEXT_POSITIVE};
+  color: ${({ theme, error }) => (error ? theme.TEXT_DANGER : theme.TEXT_POSITIVE)};
   pointer-events: ${({ error }) => !error && "none"};
   background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
   box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};

+ 1 - 1
src/components/GoogleAnalytics/index.tsx

@@ -1,5 +1,5 @@
-import Script from "next/script";
 import React from "react";
+import Script from "next/script";
 
 const isDevelopment = process.env.NODE_ENV === "development";
 

+ 10 - 18
src/components/Graph/index.tsx

@@ -38,15 +38,11 @@ const StyledEditorWrapper = styled.div<{ isWidget: boolean }>`
   }
 `;
 
-const GraphComponent = ({
-  isWidget,
-  openModal,
-  setSelectedNode,
-}: LayoutProps) => {
-  const setConfig = useConfig((state) => state.setConfig);
-  const layout = useConfig((state) => state.layout);
-  const nodes = useGraph((state) => state.nodes);
-  const edges = useGraph((state) => state.edges);
+const GraphComponent = ({ isWidget, openModal, setSelectedNode }: LayoutProps) => {
+  const setConfig = useConfig(state => state.setConfig);
+  const layout = useConfig(state => state.layout);
+  const nodes = useGraph(state => state.nodes);
+  const edges = useGraph(state => state.edges);
 
   const [size, setSize] = React.useState({
     width: 2000,
@@ -89,10 +85,8 @@ const GraphComponent = ({
         zoomAnimation={{ animationType: "linear" }}
         doubleClick={{ disabled: true }}
         onInit={onInit}
-        onPanning={(ref) =>
-          ref.instance.wrapperComponent?.classList.add("dragging")
-        }
-        onPanningStop={(ref) =>
+        onPanning={ref => ref.instance.wrapperComponent?.classList.add("dragging")}
+        onPanningStop={ref =>
           ref.instance.wrapperComponent?.classList.remove("dragging")
         }
       >
@@ -118,10 +112,8 @@ const GraphComponent = ({
             dragEdge={null}
             dragNode={null}
             fit={true}
-            node={(props) => (
-              <CustomNode {...props} onClick={handleNodeClick} />
-            )}
-            edge={(props) => (
+            node={props => <CustomNode {...props} onClick={handleNodeClick} />}
+            edge={props => (
               <Edge {...props} containerClassName={`edge-${props.id}`} />
             )}
           />
@@ -131,4 +123,4 @@ const GraphComponent = ({
   );
 };
 
-export const Graph = React.memo(GraphComponent);
+export const Graph = React.memo(GraphComponent);

+ 1 - 3
src/components/Input/index.tsx

@@ -16,6 +16,4 @@ const StyledInput = styled.input`
 
 type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
 
-export const Input: React.FC<InputProps> = (props) => (
-  <StyledInput {...props} />
-);
+export const Input: React.FC<InputProps> = props => <StyledInput {...props} />;

+ 3 - 3
src/components/Modal/index.tsx

@@ -1,8 +1,8 @@
 import React from "react";
-import { ReactComponent } from "src/typings/global";
 import { Button } from "src/components/Button";
-import * as Styled from "./styles";
 import useKeyPress from "src/hooks/useKeyPress";
+import { ReactComponent } from "src/typings/global";
+import * as Styled from "./styles";
 
 type ControlProps = React.PropsWithChildren<{
   setVisible: (status: boolean) => void;
@@ -53,7 +53,7 @@ const Modal: React.FC<React.PropsWithChildren<ModalProps>> & ModalTypes = ({
 }) => {
   const onClick = (e: React.SyntheticEvent<HTMLDivElement>) => {
     if (e.currentTarget === e.target) {
-      setVisible((v) => !v);
+      setVisible(v => !v);
     }
   };
 

+ 8 - 10
src/components/MonacoEditor/index.tsx

@@ -1,11 +1,11 @@
 import React from "react";
-import styled from "styled-components";
 import Editor, { loader } from "@monaco-editor/react";
 import { Loading } from "src/components/Loading";
-import { parser } from "src/utils/jsonParser";
 import useConfig from "src/hooks/store/useConfig";
-import useStored from "src/hooks/store/useStored";
 import useGraph from "src/hooks/store/useGraph";
+import useStored from "src/hooks/store/useStored";
+import { parser } from "src/utils/jsonParser";
+import styled from "styled-components";
 
 loader.config({
   paths: {
@@ -32,15 +32,13 @@ export const MonacoEditor = ({
 }: {
   setHasError: (value: boolean) => void;
 }) => {
-  const json = useConfig((state) => state.json);
-  const expand = useConfig((state) => state.expand);
-  const setJson = useConfig((state) => state.setJson);
-  const setGraphValue = useGraph((state) => state.setGraphValue);
+  const json = useConfig(state => state.json);
+  const expand = useConfig(state => state.expand);
+  const setJson = useConfig(state => state.setJson);
+  const setGraphValue = useGraph(state => state.setGraphValue);
   const [value, setValue] = React.useState<string | undefined>("");
 
-  const lightmode = useStored((state) =>
-    state.lightmode ? "light" : "vs-dark"
-  );
+  const lightmode = useStored(state => (state.lightmode ? "light" : "vs-dark"));
 
   React.useEffect(() => {
     const { nodes, edges } = parser(json, expand);

+ 2 - 8
src/components/SearchInput/index.tsx

@@ -72,16 +72,10 @@ export const SearchInput: React.FC = () => {
         <StyledInput
           type="text"
           value={content.value}
-          onChange={(e) =>
-            setContent((val) => ({ ...val, value: e.target.value }))
-          }
+          onChange={e => setContent(val => ({ ...val, value: e.target.value }))}
           placeholder="Search Node"
         />
-        <StyledSearchButton
-          type="reset"
-          aria-label="search"
-          onClick={handleClear}
-        >
+        <StyledSearchButton type="reset" aria-label="search" onClick={handleClear}>
           {content.value ? (
             <IoCloseSharp size={18} />
           ) : (

+ 1 - 5
src/components/SeoTags/index.tsx

@@ -6,11 +6,7 @@ interface SeoTagsProps {
   image: string;
 }
 
-export const SeoTags: React.FC<SeoTagsProps> = ({
-  description,
-  title,
-  image,
-}) => (
+export const SeoTags: React.FC<SeoTagsProps> = ({ description, title, image }) => (
   <>
     <meta name="description" content={description} />
 

+ 15 - 19
src/components/Sidebar/index.tsx

@@ -1,9 +1,7 @@
 import React from "react";
-import toast from "react-hot-toast";
 import Link from "next/link";
-import styled from "styled-components";
-import { TiFlowMerge } from "react-icons/ti";
-import { CgArrowsMergeAltH, CgArrowsShrinkH } from "react-icons/cg";
+import { useRouter } from "next/router";
+import toast from "react-hot-toast";
 import {
   AiOutlineDelete,
   AiFillGithub,
@@ -13,19 +11,20 @@ import {
   AiOutlineLink,
   AiOutlineEdit,
 } from "react-icons/ai";
+import { CgArrowsMergeAltH, CgArrowsShrinkH } from "react-icons/cg";
 import { FiDownload } from "react-icons/fi";
-
+import { HiHeart } from "react-icons/hi";
+import { MdCenterFocusWeak } from "react-icons/md";
+import { TiFlowMerge } from "react-icons/ti";
 import { Tooltip } from "src/components/Tooltip";
-import { useRouter } from "next/router";
-import { ImportModal } from "src/containers/Modals/ImportModal";
 import { ClearModal } from "src/containers/Modals/ClearModal";
+import { DownloadModal } from "src/containers/Modals/DownloadModal";
+import { ImportModal } from "src/containers/Modals/ImportModal";
 import { ShareModal } from "src/containers/Modals/ShareModal";
 import useConfig from "src/hooks/store/useConfig";
-import { HiHeart } from "react-icons/hi";
-import shallow from "zustand/shallow";
-import { MdCenterFocusWeak } from "react-icons/md";
 import { getNextLayout } from "src/utils/getNextLayout";
-import { DownloadModal } from "src/containers/Modals/DownloadModal";
+import styled from "styled-components";
+import shallow from "zustand/shallow";
 
 const StyledSidebar = styled.div`
   display: flex;
@@ -141,9 +140,9 @@ function rotateLayout(layout: "LEFT" | "RIGHT" | "DOWN" | "UP") {
 }
 
 export const Sidebar: React.FC = () => {
-  const getJson = useConfig((state) => state.getJson);
-  const setConfig = useConfig((state) => state.setConfig);
-  const centerView = useConfig((state) => state.centerView);
+  const getJson = useConfig(state => state.getJson);
+  const setConfig = useConfig(state => state.setConfig);
+  const centerView = useConfig(state => state.centerView);
   const [uploadVisible, setUploadVisible] = React.useState(false);
   const [clearVisible, setClearVisible] = React.useState(false);
   const [shareVisible, setShareVisible] = React.useState(false);
@@ -151,7 +150,7 @@ export const Sidebar: React.FC = () => {
   const { push } = useRouter();
 
   const [expand, layout, hideEditor] = useConfig(
-    (state) => [state.expand, state.layout, state.hideEditor],
+    state => [state.expand, state.layout, state.hideEditor],
     shallow
   );
 
@@ -261,10 +260,7 @@ export const Sidebar: React.FC = () => {
       <ImportModal visible={uploadVisible} setVisible={setUploadVisible} />
       <ClearModal visible={clearVisible} setVisible={setClearVisible} />
       <ShareModal visible={shareVisible} setVisible={setShareVisible} />
-      <DownloadModal
-        visible={isDownloadVisible}
-        setVisible={setDownloadVisible}
-      />
+      <DownloadModal visible={isDownloadVisible} setVisible={setDownloadVisible} />
     </StyledSidebar>
   );
 };

+ 2 - 2
src/components/Sponsors/index.tsx

@@ -8,7 +8,7 @@ async function getSponsors() {
     const data = await res.json();
 
     if (data.sponsors) {
-      return data.sponsors.map((user) => ({
+      return data.sponsors.map(user => ({
         handle: user.handle,
         avatar: user.avatar,
         profile: user.profile,
@@ -83,7 +83,7 @@ export const Sponsors = () => {
 
   return (
     <StyledSponsorsWrapper>
-      {sponsors.users.map((user) => (
+      {sponsors.users.map(user => (
         <StyledSponsor handle={user.handle} key={user.handle}>
           <a href={user.profile} target="_blank" rel="noreferrer">
             <img

+ 2 - 6
src/components/Toggle/index.tsx

@@ -1,6 +1,6 @@
 import React from "react";
-import styled from "styled-components";
 import { IoIosCheckmarkCircle, IoMdCloseCircle } from "react-icons/io";
+import styled from "styled-components";
 
 interface ToggleProps {
   checked?: boolean;
@@ -39,11 +39,7 @@ const StyledToggle = styled.div<{ active: boolean }>`
   }
 `;
 
-const Toggle: React.FC<ToggleProps> = ({
-  children,
-  checked = false,
-  onChange,
-}) => {
+const Toggle: React.FC<ToggleProps> = ({ children, checked = false, onChange }) => {
   const [isChecked, setIsChecked] = React.useState(checked);
 
   const handleClick = () => {

+ 2 - 2
src/components/Tooltip/index.tsx

@@ -38,8 +38,8 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
     transform: translate(-90%, 50%);
     border-width: 8px;
     border-style: solid;
-    border-color: transparent ${({ theme }) => theme.BACKGROUND_PRIMARY}
-      transparent transparent;
+    border-color: transparent ${({ theme }) => theme.BACKGROUND_PRIMARY} transparent
+      transparent;
   }
 
   @media only screen and (max-width: 768px) {

+ 2 - 4
src/components/__tests__/Button.test.tsx

@@ -1,12 +1,10 @@
 import React from "react";
-import { Button } from "src/components/Button";
 import { screen, render } from "@testing-library/react";
+import { Button } from "src/components/Button";
 
 describe("Button", () => {
   it("should render Button component", () => {
     render(<Button>Click Me!</Button>);
-    expect(
-      screen.getByRole("button", { name: /Click Me/ })
-    ).toBeInTheDocument();
+    expect(screen.getByRole("button", { name: /Click Me/ })).toBeInTheDocument();
   });
 });

+ 1 - 5
src/constants/data.ts

@@ -18,11 +18,7 @@ const sampleJson = Object.freeze({
       name: "Madame Uppercut",
       age: 39,
       secretIdentity: "Jane Wilson",
-      powers: [
-        "Million tonne punch",
-        "Damage resistance",
-        "Superhuman reflexes",
-      ],
+      powers: ["Million tonne punch", "Damage resistance", "Superhuman reflexes"],
     },
     {
       name: "Eternal Flame",

+ 1 - 1
src/containers/Editor/JsonEditor/index.tsx

@@ -1,7 +1,7 @@
 import React from "react";
-import styled from "styled-components";
 import { ErrorContainer } from "src/components/ErrorContainer";
 import { MonacoEditor } from "src/components/MonacoEditor";
+import styled from "styled-components";
 
 const StyledEditorWrapper = styled.div`
   display: flex;

+ 9 - 11
src/containers/Editor/LiveEditor/GraphCanvas.tsx

@@ -1,32 +1,30 @@
 import React from "react";
+import { Graph } from "src/components/Graph";
 import { NodeModal } from "src/containers/Modals/NodeModal";
 import useGraph from "src/hooks/store/useGraph";
-import { Graph } from "src/components/Graph";
 
 export const GraphCanvas = ({ isWidget = false }: { isWidget?: boolean }) => {
   const [isModalVisible, setModalVisible] = React.useState(false);
-  const [selectedNode, setSelectedNode] = React.useState<[string, string][]>(
-    []
-  );
+  const [selectedNode, setSelectedNode] = React.useState<[string, string][]>([]);
 
   const openModal = React.useCallback(() => setModalVisible(true), []);
 
-  const collapsedNodes = useGraph((state) => state.collapsedNodes);
-  const collapsedEdges = useGraph((state) => state.collapsedEdges);
+  const collapsedNodes = useGraph(state => state.collapsedNodes);
+  const collapsedEdges = useGraph(state => state.collapsedEdges);
 
   React.useEffect(() => {
-    const nodeList = collapsedNodes.map((id) => `[id$="node-${id}"]`);
-    const edgeList = collapsedEdges.map((id) => `[class$="edge-${id}"]`);
+    const nodeList = collapsedNodes.map(id => `[id$="node-${id}"]`);
+    const edgeList = collapsedEdges.map(id => `[class$="edge-${id}"]`);
 
     const hiddenItems = document.querySelectorAll(".hide");
-    hiddenItems.forEach((item) => item.classList.remove("hide"));
+    hiddenItems.forEach(item => item.classList.remove("hide"));
 
     if (nodeList.length) {
       const selectedNodes = document.querySelectorAll(nodeList.join(","));
       const selectedEdges = document.querySelectorAll(edgeList.join(","));
 
-      selectedNodes.forEach((node) => node.classList.add("hide"));
-      selectedEdges.forEach((edge) => edge.classList.add("hide"));
+      selectedNodes.forEach(node => node.classList.add("hide"));
+      selectedEdges.forEach(edge => edge.classList.add("hide"));
     }
   }, [collapsedNodes, collapsedEdges]);
 

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

@@ -1,7 +1,7 @@
 import React from "react";
-import styled from "styled-components";
-import { Tools } from "src/containers/Editor/Tools";
 import { GraphCanvas } from "src/containers/Editor/LiveEditor/GraphCanvas";
+import { Tools } from "src/containers/Editor/Tools";
+import styled from "styled-components";
 
 const StyledLiveEditor = styled.div`
   position: relative;

+ 6 - 9
src/containers/Editor/Panes.tsx

@@ -1,10 +1,10 @@
-import { Allotment } from "allotment";
 import React from "react";
-import { JsonEditor } from "src/containers/Editor/JsonEditor";
 import dynamic from "next/dynamic";
+import { Allotment } from "allotment";
+import "allotment/dist/style.css";
+import { JsonEditor } from "src/containers/Editor/JsonEditor";
 import useConfig from "src/hooks/store/useConfig";
 import styled from "styled-components";
-import "allotment/dist/style.css";
 
 export const StyledEditor = styled(Allotment)`
   position: relative !important;
@@ -17,8 +17,8 @@ const LiveEditor = dynamic(() => import("src/containers/Editor/LiveEditor"), {
 });
 
 const Panes: React.FC = () => {
-  const hideEditor = useConfig((state) => state.hideEditor);
-  const setConfig = useConfig((state) => state.setConfig);
+  const hideEditor = useConfig(state => state.hideEditor);
+  const setConfig = useConfig(state => state.setConfig);
   const isMobile = window.innerWidth <= 768;
 
   React.useEffect(() => {
@@ -35,10 +35,7 @@ const Panes: React.FC = () => {
       >
         <JsonEditor />
       </Allotment.Pane>
-      <Allotment.Pane
-        minSize={0}
-        maxSize={isMobile && !hideEditor ? 0 : Infinity}
-      >
+      <Allotment.Pane minSize={0} maxSize={isMobile && !hideEditor ? 0 : Infinity}>
         <LiveEditor />
       </Allotment.Pane>
     </StyledEditor>

+ 11 - 21
src/containers/Editor/Tools.tsx

@@ -1,17 +1,13 @@
 import React from "react";
-import {
-  AiOutlineFullscreen,
-  AiOutlineMinus,
-  AiOutlinePlus,
-} from "react-icons/ai";
+import { AiOutlineFullscreen, AiOutlineMinus, AiOutlinePlus } from "react-icons/ai";
 import { FiDownload } from "react-icons/fi";
 import { MdCenterFocusWeak } from "react-icons/md";
+import { TbSettings } from "react-icons/tb";
 import { SearchInput } from "src/components/SearchInput";
-import styled from "styled-components";
+import { SettingsModal } from "src/containers/Modals/SettingsModal";
 import useConfig from "src/hooks/store/useConfig";
+import styled from "styled-components";
 import { DownloadModal } from "../Modals/DownloadModal";
-import { TbSettings } from "react-icons/tb";
-import { SettingsModal } from "src/containers/Modals/SettingsModal";
 
 export const StyledTools = styled.div`
   position: relative;
@@ -55,12 +51,12 @@ export const Tools: React.FC = () => {
   const [settingsVisible, setSettingsVisible] = React.useState(false);
   const [isDownloadVisible, setDownloadVisible] = React.useState(false);
 
-  const hideEditor = useConfig((state) => state.hideEditor);
-  const setConfig = useConfig((state) => state.setConfig);
+  const hideEditor = useConfig(state => state.hideEditor);
+  const setConfig = useConfig(state => state.setConfig);
 
-  const zoomIn = useConfig((state) => state.zoomIn);
-  const zoomOut = useConfig((state) => state.zoomOut);
-  const centerView = useConfig((state) => state.centerView);
+  const zoomIn = useConfig(state => state.zoomIn);
+  const zoomOut = useConfig(state => state.zoomOut);
+  const centerView = useConfig(state => state.centerView);
   const toggleEditor = () => setConfig("hideEditor", !hideEditor);
 
   return (
@@ -92,14 +88,8 @@ export const Tools: React.FC = () => {
           <AiOutlinePlus />
         </StyledToolElement>
       </StyledTools>
-      <DownloadModal
-        visible={isDownloadVisible}
-        setVisible={setDownloadVisible}
-      />
-      <SettingsModal
-        visible={settingsVisible}
-        setVisible={setSettingsVisible}
-      />
+      <DownloadModal visible={isDownloadVisible} setVisible={setDownloadVisible} />
+      <SettingsModal visible={settingsVisible} setVisible={setSettingsVisible} />
     </>
   );
 };

+ 18 - 23
src/containers/Home/index.tsx

@@ -2,7 +2,6 @@ import React from "react";
 import Head from "next/head";
 import Link from "next/link";
 import { useRouter } from "next/router";
-import { TwitterTweetEmbed } from "react-twitter-embed";
 import { FaGithub, FaHeart, FaLinkedin, FaTwitter } from "react-icons/fa";
 import {
   HiCursorClick,
@@ -10,8 +9,9 @@ import {
   HiOutlineDownload,
   HiOutlineSearchCircle,
 } from "react-icons/hi";
-import { Producthunt } from "src/components/Producthunt";
+import { TwitterTweetEmbed } from "react-twitter-embed";
 import { CarbonAds } from "src/components/CarbonAds";
+import { Producthunt } from "src/components/Producthunt";
 import { Sponsors } from "src/components/Sponsors";
 import { GoalsModal } from "src/containers/Modals/GoalsModal";
 import pkg from "../../../package.json";
@@ -46,8 +46,8 @@ const HeroSection = () => {
       </Styles.StyledTitle>
       <Styles.StyledSubTitle>
         Seamlessly visualize your JSON data{" "}
-        <Styles.StyledHighlightedText>instantly</Styles.StyledHighlightedText>{" "}
-        into graphs.
+        <Styles.StyledHighlightedText>instantly</Styles.StyledHighlightedText> into
+        graphs.
       </Styles.StyledSubTitle>
       <Styles.StyledMinorTitle>Paste - Import - Fetch!</Styles.StyledMinorTitle>
       <Styles.StyledButton rel="prefetch" href="/editor" target="_blank" link>
@@ -84,9 +84,9 @@ const FeaturesSection = () => (
       </Styles.StyledCardIcon>
       <Styles.StyledCardTitle>EASY-TO-USE</Styles.StyledCardTitle>
       <Styles.StyledCardDescription>
-        Don&apos;t even bother to update your schema to view your JSON into
-        graphs; directly paste, import or fetch! JSON Crack helps you to
-        visualize without any additional values and save your time.
+        Don&apos;t even bother to update your schema to view your JSON into graphs;
+        directly paste, import or fetch! JSON Crack helps you to visualize without
+        any additional values and save your time.
       </Styles.StyledCardDescription>
     </Styles.StyledSectionCard>
 
@@ -97,9 +97,8 @@ const FeaturesSection = () => (
       <Styles.StyledCardTitle>SEARCH</Styles.StyledCardTitle>
       <Styles.StyledCardDescription>
         Have a huge file of values, keys or arrays? Worry no more, type in the
-        keyword you are looking for into search input and it will take you to
-        each node with matching result highlighting the line to understand
-        better!
+        keyword you are looking for into search input and it will take you to each
+        node with matching result highlighting the line to understand better!
       </Styles.StyledCardDescription>
     </Styles.StyledSectionCard>
 
@@ -109,8 +108,8 @@ const FeaturesSection = () => (
       </Styles.StyledCardIcon>
       <Styles.StyledCardTitle>DOWNLOAD</Styles.StyledCardTitle>
       <Styles.StyledCardDescription>
-        Download the graph to your local machine and use it wherever you want,
-        to your blogs, website or make it a poster and paste to the wall. Who
+        Download the graph to your local machine and use it wherever you want, to
+        your blogs, website or make it a poster and paste to the wall. Who
         wouldn&apos;t want to see a JSON Crack graph onto their wall, eh?
       </Styles.StyledCardDescription>
     </Styles.StyledSectionCard>
@@ -121,10 +120,9 @@ const FeaturesSection = () => (
       </Styles.StyledCardIcon>
       <Styles.StyledCardTitle>LIVE</Styles.StyledCardTitle>
       <Styles.StyledCardDescription>
-        With Microsoft&apos;s Monaco Editor which is also used by VS Code,
-        easily edit your JSON and directly view through the graphs. Also
-        there&apos;s a JSON validator above of it to make sure there is no type
-        error.
+        With Microsoft&apos;s Monaco Editor which is also used by VS Code, easily
+        edit your JSON and directly view through the graphs. Also there&apos;s a JSON
+        validator above of it to make sure there is no type error.
       </Styles.StyledCardDescription>
     </Styles.StyledSectionCard>
   </Styles.StyledFeaturesSection>
@@ -143,8 +141,8 @@ const GitHubSection = () => (
       <Styles.StyledSubTitle>Open Source Community</Styles.StyledSubTitle>
       <Styles.StyledMinorTitle>
         Join the Open Source Community by suggesting new ideas, support by
-        contributing; implementing new features, fixing bugs and doing changes
-        minor to major!
+        contributing; implementing new features, fixing bugs and doing changes minor
+        to major!
       </Styles.StyledMinorTitle>
       <Styles.StyledButton
         href="https://github.com/AykutSarac/jsoncrack.com"
@@ -178,9 +176,7 @@ const SupportSection = () => (
       <Styles.StyledSubTitle>
         Support JSON Crack at
         <br />
-        <Styles.StyledHighlightedText>
-          Product Hunt
-        </Styles.StyledHighlightedText>
+        <Styles.StyledHighlightedText>Product Hunt</Styles.StyledHighlightedText>
       </Styles.StyledSubTitle>
       <Producthunt />
     </Styles.StyledProducthunt>
@@ -195,8 +191,7 @@ const SponsorSection = () => (
   <Styles.StyledSponsorSection id="sponsor">
     <Styles.StyledSubTitle>Sponsors</Styles.StyledSubTitle>
     <Styles.StyledMinorTitle>
-      Your supports make JSON Crack possible to continue and accessible for
-      everyone!
+      Your supports make JSON Crack possible to continue and accessible for everyone!
     </Styles.StyledMinorTitle>
     <Styles.StyledButton
       href="https://github.com/sponsors/AykutSarac"

+ 1 - 1
src/containers/Home/styles.tsx

@@ -114,7 +114,7 @@ export const StyledMinorTitle = styled.p`
 export const StyledButton = styled(Button)`
   background: ${({ status }) => !status && "#a13cc2"};
   padding: 12px 24px;
-  
+
   div {
     font-family: "Roboto", sans-serif;
     font-weight: 700;

+ 1 - 1
src/containers/Modals/ClearModal/index.tsx

@@ -5,7 +5,7 @@ import { Modal, ModalProps } from "src/components/Modal";
 import useConfig from "src/hooks/store/useConfig";
 
 export const ClearModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
-  const setJson = useConfig((state) => state.setJson);
+  const setJson = useConfig(state => state.setJson);
 
   const handleClear = () => {
     setJson("{}");

+ 13 - 22
src/containers/Modals/DownloadModal/index.tsx

@@ -1,14 +1,14 @@
 import React from "react";
-import { FiCopy, FiDownload } from "react-icons/fi";
 import { toBlob, toPng } from "html-to-image";
-import { Button } from "src/components/Button";
-import { Input } from "src/components/Input";
-import { Modal, ModalProps } from "src/components/Modal";
 import { TwitterPicker } from "react-color";
 import { TwitterPickerStylesProps } from "react-color/lib/components/twitter/Twitter";
-import styled from "styled-components";
 import toast from "react-hot-toast";
+import { FiCopy, FiDownload } from "react-icons/fi";
+import { Button } from "src/components/Button";
+import { Input } from "src/components/Input";
+import { Modal, ModalProps } from "src/components/Modal";
 import useConfig from "src/hooks/store/useConfig";
+import styled from "styled-components";
 
 const ColorPickerStyles: Partial<TwitterPickerStylesProps> = {
   card: {
@@ -92,11 +92,8 @@ const StyledColorIndicator = styled.div<{ color: string }>`
   border-color: rgba(0, 0, 0, 0.1);
 `;
 
-export const DownloadModal: React.FC<ModalProps> = ({
-  visible,
-  setVisible,
-}) => {
-  const setConfig = useConfig((state) => state.setConfig);
+export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
+  const setConfig = useConfig(state => state.setConfig);
   const [fileDetails, setFileDetails] = React.useState({
     filename: "jsoncrack.com",
     backgroundColor: "transparent",
@@ -108,9 +105,7 @@ export const DownloadModal: React.FC<ModalProps> = ({
       toast.loading("Copying to clipboard...", { id: "toastClipboard" });
       setConfig("performanceMode", false);
 
-      const imageElement = document.querySelector(
-        "svg[id*='ref']"
-      ) as HTMLElement;
+      const imageElement = document.querySelector("svg[id*='ref']") as HTMLElement;
 
       const blob = await toBlob(imageElement, {
         quality: fileDetails.quality,
@@ -140,9 +135,7 @@ export const DownloadModal: React.FC<ModalProps> = ({
       toast.loading("Downloading...", { id: "toastDownload" });
       setConfig("performanceMode", false);
 
-      const imageElement = document.querySelector(
-        "svg[id*='ref']"
-      ) as HTMLElement;
+      const imageElement = document.querySelector("svg[id*='ref']") as HTMLElement;
 
       const dataURI = await toPng(imageElement, {
         quality: fileDetails.quality,
@@ -159,10 +152,8 @@ export const DownloadModal: React.FC<ModalProps> = ({
     }
   };
 
-  const updateDetails = (
-    key: keyof typeof fileDetails,
-    value: string | number
-  ) => setFileDetails({ ...fileDetails, [key]: value });
+  const updateDetails = (key: keyof typeof fileDetails, value: string | number) =>
+    setFileDetails({ ...fileDetails, [key]: value });
 
   return (
     <Modal visible={visible} setVisible={setVisible}>
@@ -174,7 +165,7 @@ export const DownloadModal: React.FC<ModalProps> = ({
             <Input
               placeholder="File Name"
               value={fileDetails.filename}
-              onChange={(e) => updateDetails("filename", e.target.value)}
+              onChange={e => updateDetails("filename", e.target.value)}
             />
           </StyledColorWrapper>
         </StyledContainer>
@@ -185,7 +176,7 @@ export const DownloadModal: React.FC<ModalProps> = ({
               triangle="hide"
               colors={defaultColors}
               color={fileDetails.backgroundColor}
-              onChange={(color) => updateDetails("backgroundColor", color.hex)}
+              onChange={color => updateDetails("backgroundColor", color.hex)}
               styles={{
                 default: ColorPickerStyles,
               }}

+ 3 - 3
src/containers/Modals/GoalsModal/index.tsx

@@ -41,9 +41,9 @@ export const GoalsModal = ({ visible, setVisible }) => {
       <Modal.Header>Help JSON Crack&apos;s Goals</Modal.Header>
       <Modal.Content>
         <StyledTitle>OUR GOAL</StyledTitle>
-        <b>JSON Crack&apos;s Goal</b> is to keep the service completely free and
-        open source for everyone! For the contiunity of our service and keep the
-        new updates coming we need your support to make that possible ❤️
+        <b>JSON Crack&apos;s Goal</b> is to keep the service completely free and open
+        source for everyone! For the contiunity of our service and keep the new
+        updates coming we need your support to make that possible ❤️
         <ButtonsWrapper>
           <Button
             href="https://github.com/sponsors/AykutSarac"

+ 7 - 8
src/containers/Modals/ImportModal/index.tsx

@@ -1,12 +1,11 @@
 import React from "react";
-import styled from "styled-components";
 import toast from "react-hot-toast";
-
-import { Modal, ModalProps } from "src/components/Modal";
+import { AiOutlineUpload } from "react-icons/ai";
 import { Button } from "src/components/Button";
 import { Input } from "src/components/Input";
-import { AiOutlineUpload } from "react-icons/ai";
+import { Modal, ModalProps } from "src/components/Modal";
 import useConfig from "src/hooks/store/useConfig";
+import styled from "styled-components";
 
 const StyledModalContent = styled(Modal.Content)`
   display: flex;
@@ -43,7 +42,7 @@ const StyledUploadMessage = styled.h3`
 `;
 
 export const ImportModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
-  const setJson = useConfig((state) => state.setJson);
+  const setJson = useConfig(state => state.setJson);
   const [url, setURL] = React.useState("");
   const [jsonFile, setJsonFile] = React.useState<File | null>(null);
 
@@ -57,8 +56,8 @@ export const ImportModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
 
       toast.loading("Loading...", { id: "toastFetch" });
       return fetch(url)
-        .then((res) => res.json())
-        .then((json) => {
+        .then(res => res.json())
+        .then(json => {
           setJson(JSON.stringify(json));
           setVisible(false);
         })
@@ -83,7 +82,7 @@ export const ImportModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
       <StyledModalContent>
         <Input
           value={url}
-          onChange={(e) => setURL(e.target.value)}
+          onChange={e => setURL(e.target.value)}
           type="url"
           placeholder="URL of JSON to fetch"
         />

+ 1 - 5
src/containers/Modals/NodeModal/index.tsx

@@ -25,11 +25,7 @@ const StyledTextarea = styled.textarea`
   border: none;
 `;
 
-export const NodeModal = ({
-  selectedNode,
-  visible,
-  closeModal,
-}: NodeModalProps) => {
+export const NodeModal = ({ selectedNode, visible, closeModal }: NodeModalProps) => {
   const nodeData = Array.isArray(selectedNode)
     ? Object.fromEntries(selectedNode)
     : selectedNode;

+ 3 - 3
src/containers/Modals/SettingsModal/index.tsx

@@ -20,10 +20,10 @@ export const SettingsModal: React.FC<{
   visible: boolean;
   setVisible: React.Dispatch<React.SetStateAction<boolean>>;
 }> = ({ visible, setVisible }) => {
-  const lightmode = useStored((state) => state.lightmode);
-  const setLightTheme = useStored((state) => state.setLightTheme);
+  const lightmode = useStored(state => state.lightmode);
+  const setLightTheme = useStored(state => state.setLightTheme);
   const [toggleHideCollapse, hideCollapse] = useStored(
-    (state) => [state.toggleHideCollapse, state.hideCollapse],
+    state => [state.toggleHideCollapse, state.hideCollapse],
     shallow
   );
 

+ 11 - 17
src/containers/Modals/ShareModal/index.tsx

@@ -1,13 +1,13 @@
 import React from "react";
+import { compress } from "compress-json";
 import toast from "react-hot-toast";
-import styled from "styled-components";
-import { Modal, ModalProps } from "src/components/Modal";
-import { Button } from "src/components/Button";
 import { BiErrorAlt } from "react-icons/bi";
-import { compress } from "compress-json";
-import useConfig from "src/hooks/store/useConfig";
+import { Button } from "src/components/Button";
 import { Input } from "src/components/Input";
+import { Modal, ModalProps } from "src/components/Modal";
 import { baseURL } from "src/constants/data";
+import useConfig from "src/hooks/store/useConfig";
+import styled from "styled-components";
 
 const StyledWarning = styled.p``;
 
@@ -44,7 +44,7 @@ const StyledContainer = styled.div`
 `;
 
 export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
-  const json = useConfig((state) => state.json);
+  const json = useConfig(state => state.json);
   const [encodedJson, setEncodedJson] = React.useState("");
 
   const embedText = `<iframe src="${baseURL}/widget?json=${encodedJson}" width="512" height="384" style="border: 2px solid #b9bbbe; border-radius: 6px;"></iframe>`;
@@ -54,7 +54,7 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
     if (visible) {
       const jsonEncode = compress(JSON.parse(json));
       const jsonString = JSON.stringify(jsonEncode);
-  
+
       setEncodedJson(encodeURIComponent(jsonString));
     }
   }, [json, visible]);
@@ -73,8 +73,8 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
           <StyledErrorWrapper>
             <BiErrorAlt size={60} />
             <StyledWarning>
-              Link size exceeds 5000 characters, unable to generate link for
-              file of this size!
+              Link size exceeds 5000 characters, unable to generate link for file of
+              this size!
             </StyledWarning>
           </StyledErrorWrapper>
         ) : (
@@ -83,10 +83,7 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
               Share Link
               <StyledFlex>
                 <Input value={shareURL} type="url" readOnly />
-                <Button
-                  status="SECONDARY"
-                  onClick={() => handleShare(shareURL)}
-                >
+                <Button status="SECONDARY" onClick={() => handleShare(shareURL)}>
                   Copy
                 </Button>
               </StyledFlex>
@@ -95,10 +92,7 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
               Embed into your website
               <StyledFlex>
                 <Input value={embedText} type="url" readOnly />
-                <Button
-                  status="SECONDARY"
-                  onClick={() => handleShare(embedText)}
-                >
+                <Button status="SECONDARY" onClick={() => handleShare(embedText)}>
                   Copy
                 </Button>
               </StyledFlex>

+ 3 - 4
src/hooks/store/useConfig.tsx

@@ -1,6 +1,6 @@
-import create from "zustand";
-import { defaultJson } from "src/constants/data";
 import { ReactZoomPanPinchRef } from "react-zoom-pan-pinch";
+import { defaultJson } from "src/constants/data";
+import create from "zustand";
 
 interface ConfigActions {
   setJson: (json: string) => void;
@@ -58,8 +58,7 @@ const useConfig = create<Config & ConfigActions>()((set, get) => ({
     const zoomPanPinch = get().zoomPanPinch;
     if (zoomPanPinch) zoomPanPinch.centerView(0.6);
   },
-  setConfig: (setting: keyof Config, value: unknown) =>
-    set({ [setting]: value }),
+  setConfig: (setting: keyof Config, value: unknown) => set({ [setting]: value }),
 }));
 
 export default useConfig;

+ 14 - 10
src/hooks/store/useGraph.tsx

@@ -1,6 +1,6 @@
-import create from "zustand";
 import { getChildrenEdges } from "src/utils/getChildrenEdges";
 import { getOutgoers } from "src/utils/getOutgoers";
+import create from "zustand";
 
 export interface Graph {
   nodes: NodeData[];
@@ -32,7 +32,7 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
       collapsedEdges: [],
       [key]: value,
     }),
-  expandNodes: (nodeId) => {
+  expandNodes: nodeId => {
     const [childrenNodes, matchingNodes] = getOutgoers(
       nodeId,
       get().nodes,
@@ -41,12 +41,16 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
     );
     const childrenEdges = getChildrenEdges(childrenNodes, get().edges);
 
-    const nodeIds = childrenNodes.map((node) => node.id).concat(matchingNodes);
-    const edgeIds = childrenEdges.map((edge) => edge.id);
+    const nodeIds = childrenNodes.map(node => node.id).concat(matchingNodes);
+    const edgeIds = childrenEdges.map(edge => edge.id);
 
-    const collapsedParents = get().collapsedParents.filter((cp) => cp !== nodeId);
-    const collapsedNodes = get().collapsedNodes.filter((nodeId) => !nodeIds.includes(nodeId));
-    const collapsedEdges = get().collapsedEdges.filter((edgeId) => !edgeIds.includes(edgeId));
+    const collapsedParents = get().collapsedParents.filter(cp => cp !== nodeId);
+    const collapsedNodes = get().collapsedNodes.filter(
+      nodeId => !nodeIds.includes(nodeId)
+    );
+    const collapsedEdges = get().collapsedEdges.filter(
+      edgeId => !edgeIds.includes(edgeId)
+    );
 
     set({
       collapsedParents,
@@ -54,12 +58,12 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
       collapsedEdges,
     });
   },
-  collapseNodes: (nodeId) => {
+  collapseNodes: nodeId => {
     const [childrenNodes] = getOutgoers(nodeId, get().nodes, get().edges);
     const childrenEdges = getChildrenEdges(childrenNodes, get().edges);
 
-    const nodeIds = childrenNodes.map((node) => node.id);
-    const edgeIds = childrenEdges.map((edge) => edge.id);
+    const nodeIds = childrenNodes.map(node => node.id);
+    const edgeIds = childrenEdges.map(edge => edge.id);
 
     set({
       collapsedParents: get().collapsedParents.concat(nodeId),

+ 2 - 2
src/hooks/store/useStored.tsx

@@ -29,7 +29,7 @@ export interface Config {
 
 const useStored = create(
   persist<Config>(
-    (set) => ({
+    set => ({
       lightmode: false,
       hideCollapse: false,
       sponsors: {
@@ -40,7 +40,7 @@ const useStored = create(
         set({
           lightmode: value,
         }),
-      setSponsors: (users) =>
+      setSponsors: users =>
         set({
           sponsors: {
             users,

+ 4 - 5
src/hooks/useFocusNode.tsx

@@ -1,5 +1,4 @@
 import React from "react";
-
 import {
   searchQuery,
   cleanupHighlight,
@@ -8,21 +7,21 @@ import {
 import useConfig from "./store/useConfig";
 
 export const useFocusNode = () => {
-  const setConfig = useConfig((state) => state.setConfig);
-  const zoomPanPinch = useConfig((state) => state.zoomPanPinch);
+  const setConfig = useConfig(state => state.setConfig);
+  const zoomPanPinch = useConfig(state => state.zoomPanPinch);
   const [selectedNode, setSelectedNode] = React.useState(0);
   const [content, setContent] = React.useState({
     value: "",
     debounced: "",
   });
 
-  const skip = () => setSelectedNode((current) => current + 1);
+  const skip = () => setSelectedNode(current => current + 1);
 
   React.useEffect(() => {
     setConfig("performanceMode", !content.value.length);
 
     const debouncer = setTimeout(() => {
-      setContent((val) => ({ ...val, debounced: content.value }));
+      setContent(val => ({ ...val, debounced: content.value }));
     }, 800);
 
     return () => clearTimeout(debouncer);

+ 1 - 2
src/pages/404.tsx

@@ -1,8 +1,7 @@
 import React from "react";
 import { useRouter } from "next/router";
-import styled from "styled-components";
-
 import { Button } from "src/components/Button";
+import styled from "styled-components";
 
 const StyledNotFound = styled.div`
   display: flex;

+ 2 - 2
src/pages/Editor/index.tsx

@@ -1,8 +1,8 @@
 import React from "react";
 import Head from "next/head";
-import styled from "styled-components";
-import Panes from "src/containers/Editor/Panes";
 import { Sidebar } from "src/components/Sidebar";
+import Panes from "src/containers/Editor/Panes";
+import styled from "styled-components";
 
 export const StyledPageWrapper = styled.div`
   display: flex;

+ 6 - 7
src/pages/Widget/index.tsx

@@ -1,17 +1,16 @@
-import { decompress } from "compress-json";
+import React from "react";
 import dynamic from "next/dynamic";
 import { useRouter } from "next/router";
-import React from "react";
+import { decompress } from "compress-json";
 import { baseURL } from "src/constants/data";
 import useGraph from "src/hooks/store/useGraph";
 import { isValidJson } from "src/utils/isValidJson";
 import { parser } from "src/utils/jsonParser";
 import styled from "styled-components";
 
-const Graph = dynamic<any>(
-  () => import("src/components/Graph").then((c) => c.Graph),
-  { ssr: false }
-);
+const Graph = dynamic<any>(() => import("src/components/Graph").then(c => c.Graph), {
+  ssr: false,
+});
 
 const StyledAttribute = styled.a`
   position: fixed;
@@ -40,7 +39,7 @@ function inIframe() {
 
 const WidgetPage = () => {
   const { query, push } = useRouter();
-  const setGraphValue = useGraph((state) => state.setGraphValue);
+  const setGraphValue = useGraph(state => state.setGraphValue);
 
   React.useEffect(() => {
     if (query.json) {

+ 9 - 24
src/pages/_app.tsx

@@ -1,17 +1,16 @@
 import React from "react";
 import type { AppProps } from "next/app";
-import { Toaster } from "react-hot-toast";
-import { ThemeProvider } from "styled-components";
+import { useRouter } from "next/router";
 import { init } from "@sentry/nextjs";
-
+import { decompress } from "compress-json";
+import { Toaster } from "react-hot-toast";
+import { GoogleAnalytics } from "src/components/GoogleAnalytics";
 import GlobalStyle from "src/constants/globalStyle";
 import { darkTheme, lightTheme } from "src/constants/theme";
-import { GoogleAnalytics } from "src/components/GoogleAnalytics";
 import useConfig from "src/hooks/store/useConfig";
-import { decompress } from "compress-json";
-import { useRouter } from "next/router";
-import { isValidJson } from "src/utils/isValidJson";
 import useStored from "src/hooks/store/useStored";
+import { isValidJson } from "src/utils/isValidJson";
+import { ThemeProvider } from "styled-components";
 
 if (process.env.NODE_ENV !== "development") {
   init({
@@ -22,14 +21,13 @@ if (process.env.NODE_ENV !== "development") {
 
 function JsonCrack({ Component, pageProps }: AppProps) {
   const { query } = useRouter();
-  const lightmode = useStored((state) => state.lightmode);
-  const setJson = useConfig((state) => state.setJson);
+  const lightmode = useStored(state => state.lightmode);
+  const setJson = useConfig(state => state.setJson);
   const [isRendered, setRendered] = React.useState(false);
 
   React.useEffect(() => {
     const isJsonValid =
-      typeof query.json === "string" &&
-      isValidJson(decodeURIComponent(query.json));
+      typeof query.json === "string" && isValidJson(decodeURIComponent(query.json));
 
     if (isJsonValid) {
       const jsonDecoded = decompress(JSON.parse(isJsonValid));
@@ -40,19 +38,6 @@ function JsonCrack({ Component, pageProps }: AppProps) {
   }, [query.json, setJson]);
 
   React.useEffect(() => {
-    // if (!window.matchMedia("(display-mode: standalone)").matches) {
-    //   navigator.serviceWorker
-    //     ?.getRegistrations()
-    //     .then(function (registrations) {
-    //       for (let registration of registrations) {
-    //         registration.unregister();
-    //       }
-    //     })
-    //     .catch(function (err) {
-    //       console.error("Service Worker registration failed: ", err);
-    //     });
-    // }
-
     setRendered(true);
   }, []);
 

+ 2 - 5
src/pages/_document.tsx

@@ -10,17 +10,14 @@ import { SeoTags } from "src/components/SeoTags";
 import { ServerStyleSheet } from "styled-components";
 
 class MyDocument extends Document {
-  static async getInitialProps(
-    ctx: DocumentContext
-  ): Promise<DocumentInitialProps> {
+  static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
     const sheet = new ServerStyleSheet();
     const originalRenderPage = ctx.renderPage;
 
     try {
       ctx.renderPage = () =>
         originalRenderPage({
-          enhanceApp: (App) => (props) =>
-            sheet.collectStyles(<App {...props} />),
+          enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
         });
 
       const initialProps = await Document.getInitialProps(ctx);

+ 3 - 4
src/utils/getChildrenEdges.ts

@@ -2,11 +2,10 @@ export const getChildrenEdges = (
   nodes: NodeData[],
   edges: EdgeData[]
 ): EdgeData[] => {
-  const nodeIds = nodes.map((node) => node.id);
+  const nodeIds = nodes.map(node => node.id);
 
   return edges.filter(
-    (edge) =>
-      nodeIds.includes(edge.from as string) ||
-      nodeIds.includes(edge.to as string)
+    edge =>
+      nodeIds.includes(edge.from as string) || nodeIds.includes(edge.to as string)
   );
 };

+ 5 - 4
src/utils/getOutgoers.ts

@@ -8,14 +8,15 @@ export const getOutgoers = (
   const matchingNodes: string[] = [];
 
   const runner = (nodeId: string) => {
-    const outgoerIds = edges.filter((e) => e.from === nodeId).map((e) => e.to);
-    const nodeList = nodes.filter((n) => {
-      if (parent.includes(n.id) && !matchingNodes.includes(n.id)) matchingNodes.push(n.id);
+    const outgoerIds = edges.filter(e => e.from === nodeId).map(e => e.to);
+    const nodeList = nodes.filter(n => {
+      if (parent.includes(n.id) && !matchingNodes.includes(n.id))
+        matchingNodes.push(n.id);
       return outgoerIds.includes(n.id) && !parent.includes(n.id);
     });
 
     outgoerNodes.push(...nodeList);
-    nodeList.forEach((node) => runner(node.id));
+    nodeList.forEach(node => runner(node.id));
   };
 
   runner(nodeId);

+ 5 - 9
src/utils/jsonParser.ts

@@ -11,7 +11,7 @@ const calculateSize = (
   else value = text.map(([k, v]) => `${k}: ${v}`).join("\n");
 
   const lineCount = value.split("\n");
-  const lineLengths = lineCount.map((line) => line.length);
+  const lineLengths = lineCount.map(line => line.length);
   const longestLine = lineLengths.sort((a, b) => b - a)[0];
 
   const getWidth = () => {
@@ -44,11 +44,7 @@ const filterValues = ([k, v]) => {
   return true;
 };
 
-function generateChildren(
-  object: Object,
-  isExpanded = true,
-  nextId: () => string
-) {
+function generateChildren(object: Object, isExpanded = true, nextId: () => string) {
   if (!(object instanceof Object)) object = [object];
 
   return Object.entries(object)
@@ -86,13 +82,13 @@ const extract = (
   os: string[] | object[] | null,
   isExpanded = true,
   nextId = (
-    (id) => () =>
+    id => () =>
       String(++id)
   )(0)
 ) => {
   if (!os) return [];
 
-  return [os].flat().map((o) => {
+  return [os].flat().map(o => {
     const text = generateNodeData(o);
     const { width, height } = calculateSize(text, false, isExpanded);
 
@@ -134,7 +130,7 @@ export const parser = (jsonStr: string, isExpanded = true) => {
     const mappedElements = extract(json, isExpanded);
     const res = [...flatten(mappedElements), ...relationships(mappedElements)];
 
-    res.forEach((data) => {
+    res.forEach(data => {
       if (isNode(data)) {
         nodes.push(data);
       } else {

+ 2 - 2
src/utils/search.ts

@@ -5,7 +5,7 @@ export const searchQuery = (param: string) => {
 export const cleanupHighlight = () => {
   const nodes = document.querySelectorAll("foreignObject.searched, .highlight");
 
-  nodes?.forEach((node) => {
+  nodes?.forEach(node => {
     node.classList.remove("highlight");
     node.classList.remove("searched");
   });
@@ -15,7 +15,7 @@ export const highlightMatchedNodes = (
   nodes: NodeListOf<Element>,
   selectedNode: number
 ) => {
-  nodes?.forEach((node) => {
+  nodes?.forEach(node => {
     console.log(node.parentElement?.closest("foreignObject"));
 
     node.parentElement?.closest("foreignObject")?.classList.add("searched");

+ 135 - 2
yarn.lock

@@ -48,6 +48,27 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
   integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
 
+"@babel/[email protected]":
+  version "7.17.8"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a"
+  integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==
+  dependencies:
+    "@ampproject/remapping" "^2.1.0"
+    "@babel/code-frame" "^7.16.7"
+    "@babel/generator" "^7.17.7"
+    "@babel/helper-compilation-targets" "^7.17.7"
+    "@babel/helper-module-transforms" "^7.17.7"
+    "@babel/helpers" "^7.17.8"
+    "@babel/parser" "^7.17.8"
+    "@babel/template" "^7.16.7"
+    "@babel/traverse" "^7.17.3"
+    "@babel/types" "^7.17.0"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.2"
+    json5 "^2.1.2"
+    semver "^6.3.0"
+
 "@babel/core@^7.11.1":
   version "7.18.10"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8"
@@ -111,6 +132,15 @@
     json5 "^2.2.1"
     semver "^6.3.0"
 
+"@babel/[email protected]":
+  version "7.17.7"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad"
+  integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==
+  dependencies:
+    "@babel/types" "^7.17.0"
+    jsesc "^2.5.1"
+    source-map "^0.5.0"
+
 "@babel/generator@^7.17.10", "@babel/generator@^7.7.2":
   version "7.17.10"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.10.tgz#c281fa35b0c349bbe9d02916f4ae08fc85ed7189"
@@ -120,6 +150,15 @@
     "@jridgewell/gen-mapping" "^0.1.0"
     jsesc "^2.5.1"
 
+"@babel/generator@^7.17.3", "@babel/generator@^7.17.7", "@babel/generator@^7.19.0":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.0.tgz#785596c06425e59334df2ccee63ab166b738419a"
+  integrity sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==
+  dependencies:
+    "@babel/types" "^7.19.0"
+    "@jridgewell/gen-mapping" "^0.3.2"
+    jsesc "^2.5.1"
+
 "@babel/generator@^7.18.10":
   version "7.18.12"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4"
@@ -245,6 +284,14 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
+"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.19.0":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
+  integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
+  dependencies:
+    "@babel/template" "^7.18.10"
+    "@babel/types" "^7.19.0"
+
 "@babel/helper-function-name@^7.17.9":
   version "7.17.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12"
@@ -432,6 +479,15 @@
     "@babel/traverse" "^7.18.11"
     "@babel/types" "^7.18.10"
 
+"@babel/helpers@^7.17.8":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18"
+  integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==
+  dependencies:
+    "@babel/template" "^7.18.10"
+    "@babel/traverse" "^7.19.0"
+    "@babel/types" "^7.19.0"
+
 "@babel/helpers@^7.17.9":
   version "7.17.9"
   resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a"
@@ -468,6 +524,11 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/[email protected]":
+  version "7.17.8"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240"
+  integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==
+
 "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.10":
   version "7.17.10"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.10.tgz#873b16db82a8909e0fbd7f115772f4b739f6ce78"
@@ -478,6 +539,11 @@
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4"
   integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==
 
+"@babel/parser@^7.17.3", "@babel/parser@^7.17.8", "@babel/parser@^7.19.0":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c"
+  integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==
+
 "@babel/parser@^7.18.10", "@babel/parser@^7.18.11":
   version "7.18.11"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9"
@@ -1205,6 +1271,22 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
+"@babel/[email protected]":
+  version "7.17.3"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57"
+  integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==
+  dependencies:
+    "@babel/code-frame" "^7.16.7"
+    "@babel/generator" "^7.17.3"
+    "@babel/helper-environment-visitor" "^7.16.7"
+    "@babel/helper-function-name" "^7.16.7"
+    "@babel/helper-hoist-variables" "^7.16.7"
+    "@babel/helper-split-export-declaration" "^7.16.7"
+    "@babel/parser" "^7.17.3"
+    "@babel/types" "^7.17.0"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
 "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.2":
   version "7.17.10"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.10.tgz#1ee1a5ac39f4eac844e6cf855b35520e5eb6f8b5"
@@ -1253,6 +1335,30 @@
     debug "^4.1.0"
     globals "^11.1.0"
 
+"@babel/traverse@^7.19.0":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.0.tgz#eb9c561c7360005c592cc645abafe0c3c4548eed"
+  integrity sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==
+  dependencies:
+    "@babel/code-frame" "^7.18.6"
+    "@babel/generator" "^7.19.0"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-function-name" "^7.19.0"
+    "@babel/helper-hoist-variables" "^7.18.6"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/parser" "^7.19.0"
+    "@babel/types" "^7.19.0"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
+"@babel/[email protected]":
+  version "7.17.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
+  integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.16.7"
+    to-fast-properties "^2.0.0"
+
 "@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.17.10", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
   version "7.17.10"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.10.tgz#d35d7b4467e439fcf06d195f8100e0fea7fc82c4"
@@ -1279,6 +1385,15 @@
     "@babel/helper-validator-identifier" "^7.18.6"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.19.0":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600"
+  integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==
+  dependencies:
+    "@babel/helper-string-parser" "^7.18.10"
+    "@babel/helper-validator-identifier" "^7.18.6"
+    to-fast-properties "^2.0.0"
+
 "@bcoe/v8-coverage@^0.2.3":
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -2035,6 +2150,19 @@
   resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
   integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
 
+"@trivago/prettier-plugin-sort-imports@^3.3.0":
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-3.3.0.tgz#ee4e9ec1d8e3076b95fcb94311f42f7a61eecd37"
+  integrity sha512-1y44bVZuIN0RsS3oIiGd5k8Vm3IZXYZnp4VsP2Z/S5L9WAOw43HE2clso66M2S/dDeJ+8sKPqnHsEfh39Vjs3w==
+  dependencies:
+    "@babel/core" "7.17.8"
+    "@babel/generator" "7.17.7"
+    "@babel/parser" "7.17.8"
+    "@babel/traverse" "7.17.3"
+    "@babel/types" "7.17.0"
+    javascript-natural-sort "0.7.1"
+    lodash "4.17.21"
+
 "@tsconfig/node10@^1.0.7":
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
@@ -5098,6 +5226,11 @@ jake@^10.8.5:
     filelist "^1.0.1"
     minimatch "^3.0.4"
 
[email protected]:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
+  integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
+
 jest-changed-files@^29.0.0:
   version "29.0.0"
   resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.0.0.tgz#aa238eae42d9372a413dd9a8dadc91ca1806dce0"
@@ -5865,7 +5998,7 @@ lodash.sortby@^4.7.0:
   resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
   integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==
 
-lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20:
+[email protected], lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20:
   version "4.17.21"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -7355,7 +7488,7 @@ source-map-url@^0.4.0:
   resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
   integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
 
-source-map@^0.5.6:
+source-map@^0.5.0, source-map@^0.5.6:
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
   integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==