diff --git a/packages/hooks/.eslintignore b/packages/hooks/.eslintignore new file mode 100644 index 000000000..0db9e028b --- /dev/null +++ b/packages/hooks/.eslintignore @@ -0,0 +1,4 @@ +vite.config.ts +.eslintrc.cjs +node_modules +dist \ No newline at end of file diff --git a/packages/hooks/.eslintrc.cjs b/packages/hooks/.eslintrc.cjs new file mode 100644 index 000000000..e5f2c8aad --- /dev/null +++ b/packages/hooks/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked' + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname, + }, + ignorePatterns: ['dist', '.eslintrc.cjs', 'tsup.config.ts'], + parser: '@typescript-eslint/parser', + plugins: ['react'], + rules: { + '@typescript-eslint/explicit-function-return-type': ['off'] + }, +} diff --git a/packages/hooks/.gitignore b/packages/hooks/.gitignore new file mode 100644 index 000000000..a3e304c22 --- /dev/null +++ b/packages/hooks/.gitignore @@ -0,0 +1,26 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +.eslintcache + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +dist/** \ No newline at end of file diff --git a/packages/hooks/package.json b/packages/hooks/package.json new file mode 100644 index 000000000..d9a8a74b3 --- /dev/null +++ b/packages/hooks/package.json @@ -0,0 +1,59 @@ +{ + "name": "@layer5/sistent-hooks", + "version": "0.0.0", + "description": "Reusable React Components", + "sideEffects": false, + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.js", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist/**" + ], + "scripts": { + "build": "NODE_ENV=production tsup", + "dev": "NODE_ENV=development tsup" + }, + "dependencies": { + "@reduxjs/toolkit": "^1.9.5", + "@types/cytoscape": "^3.19.10", + "@types/react": "^18.2.21", + "cytoscape": "^3.26.0", + "notistack": "^3.0.1", + "react-redux": "^8.1.2", + "redux": "^4.2.1", + "rxjs": "^7.8.1", + "tsup": "^7.2.0", + "typescript": "^5.2.2" + }, + "devDependencies": { + "@swc/core": "^1.3.96", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "eslint": "^8.53.0", + "eslint-plugin-react": "^7.33.2", + "tsconfig": "workspace:^" + }, + "optionalDependencies": { + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.js", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + } + } +} diff --git a/packages/hooks/src/context/CytoscapeProvider.ts b/packages/hooks/src/context/CytoscapeProvider.ts new file mode 100644 index 000000000..3da942fe4 --- /dev/null +++ b/packages/hooks/src/context/CytoscapeProvider.ts @@ -0,0 +1,19 @@ +import cytoscape from 'cytoscape'; +import React from 'react'; + +export interface CytoscapeContextInterface { + cytoscape: cytoscape.Core; + container: HTMLElement; +} + +export const CytoscapeContext = React.createContext(null); + +export const CytoscapeProvider = CytoscapeContext.Provider; + +export function useCytoscapeContext() { + const context = React.useContext(CytoscapeContext); + if (!context) { + throw new Error('useCytoscapeContext must be used within a CytoscapeContextProvider'); + } + return context; +} diff --git a/packages/hooks/src/context/ReduxProvider.tsx b/packages/hooks/src/context/ReduxProvider.tsx new file mode 100644 index 000000000..4b9040300 --- /dev/null +++ b/packages/hooks/src/context/ReduxProvider.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { store } from '../redux/store'; + +interface ReduxProviderProps { + children: React.ReactNode; +} + +const ReduxContext = React.createContext({}); + +export function useRedux() { + return React.useContext(ReduxContext); +} + +export function ReduxProvider({ children }: ReduxProviderProps): JSX.Element { + return ( + + {children} + + ); +} diff --git a/packages/hooks/src/context/useRedux.ts b/packages/hooks/src/context/useRedux.ts new file mode 100644 index 000000000..e164be620 --- /dev/null +++ b/packages/hooks/src/context/useRedux.ts @@ -0,0 +1,15 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { AppDispatch, RootState, store } from '../redux/store'; + +const ReduxContext = React.createContext(store); + +export function useReduxState(selector: (state: RootState) => T): T { + const store = React.useContext(ReduxContext); + return useSelector(selector); +} + +export function useReduxDispatch(): AppDispatch { + const store = React.useContext(ReduxContext); + return useDispatch(); +} diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts new file mode 100644 index 000000000..19c16567c --- /dev/null +++ b/packages/hooks/src/index.ts @@ -0,0 +1,7 @@ +export * from '.'; +export { ReduxProvider } from './context/ReduxProvider'; +export { useReduxDispatch, useReduxState } from './context/useRedux'; +export { useDebounced } from './useDebounced'; +export { useLocalStorage } from './useLocalStorage'; +export { usePauseEvent } from './usePauseEvent'; +export { useThrottledDragOver } from './useThrottledDragOver'; diff --git a/packages/hooks/src/redux/store.ts b/packages/hooks/src/redux/store.ts new file mode 100644 index 000000000..f0af22e8a --- /dev/null +++ b/packages/hooks/src/redux/store.ts @@ -0,0 +1,8 @@ +import { configureStore } from '@reduxjs/toolkit'; + +export const store = configureStore({ + reducer: {} +}); + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; diff --git a/packages/hooks/src/useCytoscape.ts b/packages/hooks/src/useCytoscape.ts new file mode 100644 index 000000000..bdb9b1820 --- /dev/null +++ b/packages/hooks/src/useCytoscape.ts @@ -0,0 +1,7 @@ +import cytoscape from 'cytoscape'; + +import { useCytoscapeContext } from './context/CytoscapeProvider'; + +export function useCytoscape(): cytoscape.Core { + return useCytoscapeContext().cytoscape; +} diff --git a/packages/hooks/src/useDebounced.ts b/packages/hooks/src/useDebounced.ts new file mode 100644 index 000000000..b15b6542c --- /dev/null +++ b/packages/hooks/src/useDebounced.ts @@ -0,0 +1,26 @@ +import React from 'react'; + +export function useDebounced void>(func: T, timeout = 500) { + const timerRef = React.useRef(); + + React.useEffect(() => { + const cleanup = () => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + }; + + return cleanup; + }, []); + + const debouncedFunction = (...args: Parameters) => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + timerRef.current = window.setTimeout(() => { + func(...args); + }, timeout); + }; + + return debouncedFunction; +} diff --git a/packages/hooks/src/useDraggable.ts b/packages/hooks/src/useDraggable.ts new file mode 100644 index 000000000..0b385e4db --- /dev/null +++ b/packages/hooks/src/useDraggable.ts @@ -0,0 +1,52 @@ +import React from 'react'; + +import { useCytoscapeContext } from './context/CytoscapeProvider'; + +export function useDraggable( + dragReference: React.RefObject, + componentReference: React.RefObject +) { + const context = useCytoscapeContext(); + const [{ dx, dy }, setOffset] = React.useState({ dx: 0, dy: 0 }); + + React.useEffect(() => { + if (!dragReference.current || !componentReference.current || !context) { + throw new Error(`An error occurred while trying to drag.`); + } + const el = dragReference.current; + + const handleMouseDown: EventListener = (event) => { + const startX = (event as MouseEvent).pageX - dx; + const startY = (event as MouseEvent).pageY - dy; + + const handleMouseMove = (event: Event) => { + const newDx = (event as MouseEvent).pageX - startX; + const newDy = (event as MouseEvent).pageY - startY; + setOffset({ dx: newDx, dy: newDy }); + }; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener( + 'mouseup', + () => { + document.removeEventListener('mousemove', handleMouseMove); + }, + { once: true } + ); + }; + + el.addEventListener('mousedown', handleMouseDown); + el.addEventListener('mouseup', handleMouseDown); + + return () => { + el.removeEventListener('mousedown', handleMouseDown); + el.removeEventListener('mouseup', handleMouseDown); + }; + }, [dx, dy, dragReference, componentReference, context]); + + React.useEffect(() => { + if (componentReference.current) { + componentReference.current.style.transform = `translate3d(${dx}px, ${dy}px, 0)`; + } + }, [componentReference, dx, dy]); +} diff --git a/packages/hooks/src/useFullScreen.ts b/packages/hooks/src/useFullScreen.ts new file mode 100644 index 000000000..11d4f28e1 --- /dev/null +++ b/packages/hooks/src/useFullScreen.ts @@ -0,0 +1,51 @@ +import React from 'react'; + +import { useCytoscapeContext } from './context/CytoscapeProvider'; + +function toggleFullScreen(dom: HTMLElement) { + if (document.fullscreenElement !== dom) { + dom.requestFullscreen().catch((err) => { + console.error('Error attempting to enable full screen:', err); + }); + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } + } +} + +export function useFullScreen(container?: HTMLElement | null): { + toggle: () => void; + isFullScreen: boolean; +} { + const context = useCytoscapeContext(); + const [isFullScreen, setFullScreen] = React.useState(false); + const [element, setElement] = React.useState( + container ? container : context.container + ); + + // const toggleState = () => setFullScreen((v) => !v) + const toggleState = React.useCallback(() => { + setFullScreen((prevState) => !prevState); + }, [setFullScreen]); + + React.useEffect(() => { + const handleFullscreenChange = () => toggleState(); + document.addEventListener('fullscreenchange', handleFullscreenChange); + + return () => document.removeEventListener('fullscreenchange', handleFullscreenChange); + }, [toggleState]); + + React.useEffect(() => { + setElement(container ?? context.container); + }, [container, context.container]); + + const toggle = React.useCallback(() => { + toggleFullScreen(element); + }, [element]); + + return { + toggle, + isFullScreen + }; +} diff --git a/packages/hooks/src/useLocalStorage.ts b/packages/hooks/src/useLocalStorage.ts new file mode 100644 index 000000000..3eb5ff23a --- /dev/null +++ b/packages/hooks/src/useLocalStorage.ts @@ -0,0 +1,15 @@ +import React from 'react'; + +export function useLocalStorage(key: string, initialValue: T): [T, (newValue: T) => void] { + const [value, setValue] = React.useState(() => { + const storedValue = localStorage.getItem(key); + return storedValue !== null ? JSON.parse(storedValue) : initialValue; + }); + + const setLocalStorageValue = (newValue: T) => { + localStorage.setItem(key, JSON.stringify(newValue)); + setValue(newValue); + }; + + return [value, setLocalStorageValue]; +} diff --git a/packages/hooks/src/useOverlayedComponent.ts b/packages/hooks/src/useOverlayedComponent.ts new file mode 100644 index 000000000..90b5f544c --- /dev/null +++ b/packages/hooks/src/useOverlayedComponent.ts @@ -0,0 +1,102 @@ +import cytoscape, { NodeCollection } from 'cytoscape'; +import React from 'react'; + +import { useCytoscapeContext } from './context/CytoscapeProvider'; + +export function useOverlayedComponent(): NodeCollection | null { + const context = useCytoscapeContext(); + const [overlayedComponent, setOverlayedComponent] = React.useState(null); + + React.useEffect(() => { + const handleMouseMove = (e: MouseEvent) => { + const position = getMousePostitionRelativeToCyCanvas(e); + const component = getOverlayedComponent(context.cytoscape, position); + setOverlayedComponent((prevComponent) => { + if (prevComponent === null) { + return component; + } else { + return component === null ? prevComponent : component; + } + }); + }; + + const cyWrapperDiv = document.getElementById('cyto-wrapper-div'); + if (cyWrapperDiv) { + cyWrapperDiv.addEventListener('mousemove', handleMouseMove); + } + + return () => { + if (cyWrapperDiv) { + cyWrapperDiv.removeEventListener('mousemove', handleMouseMove); + } + }; + }, [context.cytoscape]); + + return overlayedComponent; +} + +interface Overlayed { + x1: number; + x2: number; + y1: number; + y2: number; +} + +interface OverlayedPosition { + x: number; + y: number; +} + +export function getMousePostitionRelativeToElement( + e: MouseEvent, + element: HTMLElement +): OverlayedPosition { + const elementBoundingClientRect = element.getBoundingClientRect(); + const mouseX = e.clientX - elementBoundingClientRect.left; + const mouseY = e.clientY - elementBoundingClientRect.top; + return { x: mouseX, y: mouseY }; +} + +export function getMousePostitionRelativeToCyCanvas(e: MouseEvent): OverlayedPosition { + const cyWrapperDiv = document.getElementById('cyto-wrapper-div'); + + if (cyWrapperDiv) { + const elementBoundingClientRect = cyWrapperDiv.getBoundingClientRect(); + const mouseX = e.clientX - elementBoundingClientRect.left; + const mouseY = e.clientY - elementBoundingClientRect.top - 40; // Adjusted by 40 as per your original code + return { x: mouseX, y: mouseY }; + } + + return { x: 0, y: 0 }; +} + +export function getOverlayedComponent( + cy: cytoscape.Core, + position: OverlayedPosition +): cytoscape.NodeCollection | null { + const acceptingNodesCytoSelector = `node[type="NAMESPACE"], node[type="DEPLOYMENT"]`; + + const elements = cy.elements(acceptingNodesCytoSelector); + const overlayedParents: cytoscape.NodeCollection = cy.collection(); + + elements.forEach((ele) => { + const boundingBox = ele.boundingBox(); + if (isOverlayed(boundingBox, position)) { + overlayedParents.merge(ele); + } + }); + + if (overlayedParents.length === 0) { + return null; + } + + if (overlayedParents.length >= 1) { + return overlayedParents; + } + + return null; +} + +export function isOverlayed(bb: Overlayed, position: OverlayedPosition): boolean { + return position.x >= bb.x1 && position.x <= bb.x2 && position.y >= bb.y1 && position.y <= bb.y2; +} diff --git a/packages/hooks/src/usePauseEvent.ts b/packages/hooks/src/usePauseEvent.ts new file mode 100644 index 000000000..42d64fb46 --- /dev/null +++ b/packages/hooks/src/usePauseEvent.ts @@ -0,0 +1,11 @@ +import React from 'react'; + +export function usePauseEvent(): (e: Event) => boolean { + const pauseEvent = React.useCallback((e: Event) => { + if (e.stopPropagation) e.stopPropagation(); + if (e.preventDefault) e.preventDefault(); + return false; + }, []); + + return pauseEvent; +} diff --git a/packages/hooks/src/useThrottledDragOver.ts b/packages/hooks/src/useThrottledDragOver.ts new file mode 100644 index 000000000..1231d9390 --- /dev/null +++ b/packages/hooks/src/useThrottledDragOver.ts @@ -0,0 +1,29 @@ +import React from 'react'; +import { Observable, Subscription, fromEvent } from 'rxjs'; +import { throttleTime } from 'rxjs/operators'; + +export const useThrottledDragOver = ( + element: HTMLElement, + callback: (event: Event) => void +): Subscription | undefined => { + const subscriptionRef = React.useRef(); + + React.useEffect(() => { + const dragOver$: Observable = fromEvent(element, 'dragover').pipe( + throttleTime(100, undefined, { leading: true, trailing: true }) + ); + + const subscription: Subscription = dragOver$.subscribe(callback); + subscriptionRef.current = subscription; + + return () => { + if (subscriptionRef.current) { + subscriptionRef.current.unsubscribe(); + } + }; + }, [element, callback]); + + return subscriptionRef.current; +}; + +export default useThrottledDragOver; diff --git a/packages/hooks/tsconfig.json b/packages/hooks/tsconfig.json new file mode 100644 index 000000000..9e5182c05 --- /dev/null +++ b/packages/hooks/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "tsconfig/react-library.json", + "compilerOptions": { + "declarationMap": true, + "emitDeclarationOnly": true, + "lib": ["es2020", "DOM"], + "target": "es2020", + "module": "esnext" + }, + "include": ["."], + "exclude": ["dist", "build", "node_modules", "**/*.d.ts", "tsup.config.ts"] + } + \ No newline at end of file diff --git a/packages/hooks/tsup.config.ts b/packages/hooks/tsup.config.ts new file mode 100644 index 000000000..7f8a3f71d --- /dev/null +++ b/packages/hooks/tsup.config.ts @@ -0,0 +1,18 @@ +import path from 'path'; +import { defineConfig } from 'tsup'; + +const env = process.env.NODE_ENV; + +export default defineConfig({ + outdir: 'dist', + entry: ['src/index.ts'], + bundle: env === 'production', + clean: true, + dts: true, + format: ['cjs'], + external: ['react'], + minify: env === 'production', + watch: env === 'development', + sourcemap: env === 'development', + tsconfig: path.resolve(__dirname, './tsconfig.json') +}); diff --git a/yarn.lock b/yarn.lock index b945cc4c2..d4f6bf56f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,7 +108,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.23.1 resolution: "@babel/runtime@npm:7.23.1" dependencies: @@ -678,6 +678,23 @@ __metadata: languageName: node linkType: hard +"@eslint/eslintrc@npm:^2.1.3": + version: 2.1.3 + resolution: "@eslint/eslintrc@npm:2.1.3" + dependencies: + ajv: ^6.12.4 + debug: ^4.3.2 + espree: ^9.6.0 + globals: ^13.19.0 + ignore: ^5.2.0 + import-fresh: ^3.2.1 + js-yaml: ^4.1.0 + minimatch: ^3.1.2 + strip-json-comments: ^3.1.1 + checksum: 5c6c3878192fe0ddffa9aff08b4e2f3bcc8f1c10d6449b7295a5f58b662019896deabfc19890455ffd7e60a5bd28d25d0eaefb2f78b2d230aae3879af92b89e5 + languageName: node + linkType: hard + "@eslint/js@npm:8.50.0": version: 8.50.0 resolution: "@eslint/js@npm:8.50.0" @@ -685,6 +702,13 @@ __metadata: languageName: node linkType: hard +"@eslint/js@npm:8.53.0": + version: 8.53.0 + resolution: "@eslint/js@npm:8.53.0" + checksum: e0d5cfb0000aaee237c8e6d6d6e366faa60b1ef7f928ce17778373aa44d3b886368f6d5e1f97f913f0f16801aad016db8b8df78418c9d18825c15590328028af + languageName: node + linkType: hard + "@exodus/schemasafe@npm:^1.0.0-rc.2": version: 1.3.0 resolution: "@exodus/schemasafe@npm:1.3.0" @@ -741,6 +765,17 @@ __metadata: languageName: node linkType: hard +"@humanwhocodes/config-array@npm:^0.11.13": + version: 0.11.13 + resolution: "@humanwhocodes/config-array@npm:0.11.13" + dependencies: + "@humanwhocodes/object-schema": ^2.0.1 + debug: ^4.1.1 + minimatch: ^3.0.5 + checksum: f8ea57b0d7ed7f2d64cd3944654976829d9da91c04d9c860e18804729a33f7681f78166ef4c761850b8c324d362f7d53f14c5c44907a6b38b32c703ff85e4805 + languageName: node + linkType: hard + "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" @@ -755,6 +790,13 @@ __metadata: languageName: node linkType: hard +"@humanwhocodes/object-schema@npm:^2.0.1": + version: 2.0.1 + resolution: "@humanwhocodes/object-schema@npm:2.0.1" + checksum: 24929487b1ed48795d2f08346a0116cc5ee4634848bce64161fb947109352c562310fd159fc64dda0e8b853307f5794605191a9547f7341158559ca3c8262a45 + languageName: node + linkType: hard + "@hutson/parse-repository-url@npm:^3.0.0": version: 3.0.2 resolution: "@hutson/parse-repository-url@npm:3.0.2" @@ -944,6 +986,36 @@ __metadata: languageName: unknown linkType: soft +"@layer5/sistent-hooks@workspace:packages/hooks": + version: 0.0.0-use.local + resolution: "@layer5/sistent-hooks@workspace:packages/hooks" + dependencies: + "@reduxjs/toolkit": ^1.9.5 + "@swc/core": ^1.3.96 + "@types/cytoscape": ^3.19.10 + "@types/react": ^18.2.21 + "@typescript-eslint/eslint-plugin": ^6.10.0 + "@typescript-eslint/parser": ^6.10.0 + cytoscape: ^3.26.0 + eslint: ^8.53.0 + eslint-plugin-react: ^7.33.2 + notistack: ^3.0.1 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-redux: ^8.1.2 + redux: ^4.2.1 + rxjs: ^7.8.1 + tsconfig: "workspace:^" + tsup: ^7.2.0 + typescript: ^5.2.2 + dependenciesMeta: + react: + optional: true + react-dom: + optional: true + languageName: unknown + linkType: soft + "@layer5/sistent-svg@^0.12.0, @layer5/sistent-svg@workspace:packages/svg": version: 0.0.0-use.local resolution: "@layer5/sistent-svg@workspace:packages/svg" @@ -1803,7 +1875,7 @@ __metadata: languageName: node linkType: hard -"@reduxjs/toolkit@npm:^1.9.6": +"@reduxjs/toolkit@npm:^1.9.5, @reduxjs/toolkit@npm:^1.9.6": version: 1.9.6 resolution: "@reduxjs/toolkit@npm:1.9.6" dependencies: @@ -1906,6 +1978,136 @@ __metadata: languageName: node linkType: hard +"@swc/core-darwin-arm64@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-darwin-arm64@npm:1.3.96" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@swc/core-darwin-x64@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-darwin-x64@npm:1.3.96" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@swc/core-linux-arm-gnueabihf@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.96" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@swc/core-linux-arm64-gnu@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.96" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-arm64-musl@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.96" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@swc/core-linux-x64-gnu@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.96" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-x64-musl@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-linux-x64-musl@npm:1.3.96" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@swc/core-win32-arm64-msvc@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.96" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@swc/core-win32-ia32-msvc@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.96" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@swc/core-win32-x64-msvc@npm:1.3.96": + version: 1.3.96 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.96" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@swc/core@npm:^1.3.96": + version: 1.3.96 + resolution: "@swc/core@npm:1.3.96" + dependencies: + "@swc/core-darwin-arm64": 1.3.96 + "@swc/core-darwin-x64": 1.3.96 + "@swc/core-linux-arm-gnueabihf": 1.3.96 + "@swc/core-linux-arm64-gnu": 1.3.96 + "@swc/core-linux-arm64-musl": 1.3.96 + "@swc/core-linux-x64-gnu": 1.3.96 + "@swc/core-linux-x64-musl": 1.3.96 + "@swc/core-win32-arm64-msvc": 1.3.96 + "@swc/core-win32-ia32-msvc": 1.3.96 + "@swc/core-win32-x64-msvc": 1.3.96 + "@swc/counter": ^0.1.1 + "@swc/types": ^0.1.5 + peerDependencies: + "@swc/helpers": ^0.5.0 + dependenciesMeta: + "@swc/core-darwin-arm64": + optional: true + "@swc/core-darwin-x64": + optional: true + "@swc/core-linux-arm-gnueabihf": + optional: true + "@swc/core-linux-arm64-gnu": + optional: true + "@swc/core-linux-arm64-musl": + optional: true + "@swc/core-linux-x64-gnu": + optional: true + "@swc/core-linux-x64-musl": + optional: true + "@swc/core-win32-arm64-msvc": + optional: true + "@swc/core-win32-ia32-msvc": + optional: true + "@swc/core-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@swc/helpers": + optional: true + checksum: 41d4a4461b2952aaf8d3be945d373d0f3bd126115ee1aad0f76f2690e2b5635b6ec5bb54a7638deb9afedb1ad6f7d8453468a704e54e5fbb8234dd4a43b80205 + languageName: node + linkType: hard + +"@swc/counter@npm:^0.1.1": + version: 0.1.2 + resolution: "@swc/counter@npm:0.1.2" + checksum: 8427c594f1f0cf44b83885e9c8fe1e370c9db44ae96e07a37c117a6260ee97797d0709483efbcc244e77bac578690215f45b23254c4cd8a70fb25ddbb50bf33e + languageName: node + linkType: hard + +"@swc/types@npm:^0.1.5": + version: 0.1.5 + resolution: "@swc/types@npm:0.1.5" + checksum: 6aee11f62d3d805a64848e0bd5f0e0e615f958e327a9e1260056c368d7d28764d89e38bd8005a536c9bf18afbcd303edd84099d60df34a2975d62540f61df13b + languageName: node + linkType: hard + "@testing-library/dom@npm:^9.0.0": version: 9.3.3 resolution: "@testing-library/dom@npm:9.3.3" @@ -1995,6 +2197,13 @@ __metadata: languageName: node linkType: hard +"@types/cytoscape@npm:^3.19.10": + version: 3.19.11 + resolution: "@types/cytoscape@npm:3.19.11" + checksum: 6c4a1ba52b416d70c6f8e00b5a5c474e1f2cae5150682c3e6976f6c8ac6b99cab99bcc5887640149901e6704f38627b58e3face8620bff8dac94404329164d8b + languageName: node + linkType: hard + "@types/hoist-non-react-statics@npm:^3.3.1": version: 3.3.2 resolution: "@types/hoist-non-react-statics@npm:3.3.2" @@ -2157,7 +2366,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^18.2.15": +"@types/react@npm:*, @types/react@npm:^18.2.15, @types/react@npm:^18.2.21": version: 18.2.23 resolution: "@types/react@npm:18.2.23" dependencies: @@ -2189,6 +2398,13 @@ __metadata: languageName: node linkType: hard +"@types/use-sync-external-store@npm:^0.0.3": + version: 0.0.3 + resolution: "@types/use-sync-external-store@npm:0.0.3" + checksum: 161ddb8eec5dbe7279ac971531217e9af6b99f7783213566d2b502e2e2378ea19cf5e5ea4595039d730aa79d3d35c6567d48599f69773a02ffcff1776ec2a44e + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 21.0.1 resolution: "@types/yargs-parser@npm:21.0.1" @@ -2230,6 +2446,31 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:^6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.10.0" + dependencies: + "@eslint-community/regexpp": ^4.5.1 + "@typescript-eslint/scope-manager": 6.10.0 + "@typescript-eslint/type-utils": 6.10.0 + "@typescript-eslint/utils": 6.10.0 + "@typescript-eslint/visitor-keys": 6.10.0 + debug: ^4.3.4 + graphemer: ^1.4.0 + ignore: ^5.2.4 + natural-compare: ^1.4.0 + semver: ^7.5.4 + ts-api-utils: ^1.0.1 + peerDependencies: + "@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: eaf1f66ae1915426dad8d229c8cb80d2b320572a30c3fbc57d560d40edc2d17d004101a2fcbe331bc458df19a00f8b705f2442ee02e028bb595f4e9f9152e99d + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:^5.4.2 || ^6.0.0, @typescript-eslint/parser@npm:^6.0.0": version: 6.7.3 resolution: "@typescript-eslint/parser@npm:6.7.3" @@ -2248,6 +2489,34 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:^6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/parser@npm:6.10.0" + dependencies: + "@typescript-eslint/scope-manager": 6.10.0 + "@typescript-eslint/types": 6.10.0 + "@typescript-eslint/typescript-estree": 6.10.0 + "@typescript-eslint/visitor-keys": 6.10.0 + debug: ^4.3.4 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: c4b140932d639b3f3eac892497aa700bcc9101ef268285020757dc9bee670d122de107e936320af99a5c06569e4eb93bccf87f14a9970ceab708c432e748423a + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/scope-manager@npm:6.10.0" + dependencies: + "@typescript-eslint/types": 6.10.0 + "@typescript-eslint/visitor-keys": 6.10.0 + checksum: c9b9483082ae853f10b888cf04d4a14f666ac55e749bfdb7b7f726fc51127a6340b5e2f50d93f134a8854ddcc41f7b116b214753251a8b033d0d84c600439c54 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:6.7.3": version: 6.7.3 resolution: "@typescript-eslint/scope-manager@npm:6.7.3" @@ -2258,6 +2527,23 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/type-utils@npm:6.10.0" + dependencies: + "@typescript-eslint/typescript-estree": 6.10.0 + "@typescript-eslint/utils": 6.10.0 + debug: ^4.3.4 + ts-api-utils: ^1.0.1 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: cfe9520cf0c0f50b115d2591acb2abf99ffe5789b3536268ca65b624c8498812d91f187e80c41bea7cf2cebad9c38f69ef27440f872a20fb53c59856d8f5df38 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:6.7.3": version: 6.7.3 resolution: "@typescript-eslint/type-utils@npm:6.7.3" @@ -2275,6 +2561,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/types@npm:6.10.0" + checksum: e63a9e05eb3d736d02a09131627d5cb89394bf0d9d6b46fb4b620be902d89d73554720be65acbc194787bff9ffcd518c9a6cf88fd63e418232b4181e8d8438df + languageName: node + linkType: hard + "@typescript-eslint/types@npm:6.7.3": version: 6.7.3 resolution: "@typescript-eslint/types@npm:6.7.3" @@ -2282,6 +2575,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.10.0" + dependencies: + "@typescript-eslint/types": 6.10.0 + "@typescript-eslint/visitor-keys": 6.10.0 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.5.4 + ts-api-utils: ^1.0.1 + peerDependenciesMeta: + typescript: + optional: true + checksum: 15bd8d9239a557071d6b03e7aa854b769fcc2dbdff587ed94be7ee8060dabdb05bcae4251df22432f625f82087e7f6986e9aab04f7eea35af694d4edd76a21af + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:6.7.3": version: 6.7.3 resolution: "@typescript-eslint/typescript-estree@npm:6.7.3" @@ -2300,6 +2611,23 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/utils@npm:6.10.0" + dependencies: + "@eslint-community/eslint-utils": ^4.4.0 + "@types/json-schema": ^7.0.12 + "@types/semver": ^7.5.0 + "@typescript-eslint/scope-manager": 6.10.0 + "@typescript-eslint/types": 6.10.0 + "@typescript-eslint/typescript-estree": 6.10.0 + semver: ^7.5.4 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + checksum: b6bd4d68623fb8d616ae63a88f2954258411a0cc113029fba801d1e74b4c0319fdfbcac0070527afe5cc38c012c8718e4faecd1603000924d7b89e8fefc3f24d + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:6.7.3": version: 6.7.3 resolution: "@typescript-eslint/utils@npm:6.7.3" @@ -2317,6 +2645,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.10.0" + dependencies: + "@typescript-eslint/types": 6.10.0 + eslint-visitor-keys: ^3.4.1 + checksum: 9640bfae41e6109ffba31e68b1720382de0538d021261e2fc9e514c83c703084393c0818ca77ed26b950273e45e593371120281e8d4bbd09cb8c2d46c9fe4f03 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:6.7.3": version: 6.7.3 resolution: "@typescript-eslint/visitor-keys@npm:6.7.3" @@ -2327,6 +2665,13 @@ __metadata: languageName: node linkType: hard +"@ungap/structured-clone@npm:^1.2.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 4f656b7b4672f2ce6e272f2427d8b0824ed11546a601d8d5412b9d7704e83db38a8d9f402ecdf2b9063fc164af842ad0ec4a55819f621ed7e7ea4d1efcc74524 + languageName: node + linkType: hard + "@yarnpkg/lockfile@npm:^1.1.0": version: 1.1.0 resolution: "@yarnpkg/lockfile@npm:1.1.0" @@ -3557,6 +3902,16 @@ __metadata: languageName: node linkType: hard +"cytoscape@npm:^3.26.0": + version: 3.26.0 + resolution: "cytoscape@npm:3.26.0" + dependencies: + heap: ^0.2.6 + lodash: ^4.17.21 + checksum: c6a3b2fbe99009cde6e5e2eb6ff2e0469b37f3e12b0828d676aa3c25a7ce7b6ed689b6765e9d3975d51c718a7870e358c639c9128352813b95eb342ef64a26b8 + languageName: node + linkType: hard + "cz-conventional-changelog@npm:3.3.0, cz-conventional-changelog@npm:^3.3.0": version: 3.3.0 resolution: "cz-conventional-changelog@npm:3.3.0" @@ -4442,6 +4797,54 @@ __metadata: languageName: node linkType: hard +"eslint@npm:^8.53.0": + version: 8.53.0 + resolution: "eslint@npm:8.53.0" + dependencies: + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.6.1 + "@eslint/eslintrc": ^2.1.3 + "@eslint/js": 8.53.0 + "@humanwhocodes/config-array": ^0.11.13 + "@humanwhocodes/module-importer": ^1.0.1 + "@nodelib/fs.walk": ^1.2.8 + "@ungap/structured-clone": ^1.2.0 + ajv: ^6.12.4 + chalk: ^4.0.0 + cross-spawn: ^7.0.2 + debug: ^4.3.2 + doctrine: ^3.0.0 + escape-string-regexp: ^4.0.0 + eslint-scope: ^7.2.2 + eslint-visitor-keys: ^3.4.3 + espree: ^9.6.1 + esquery: ^1.4.2 + esutils: ^2.0.2 + fast-deep-equal: ^3.1.3 + file-entry-cache: ^6.0.1 + find-up: ^5.0.0 + glob-parent: ^6.0.2 + globals: ^13.19.0 + graphemer: ^1.4.0 + ignore: ^5.2.0 + imurmurhash: ^0.1.4 + is-glob: ^4.0.0 + is-path-inside: ^3.0.3 + js-yaml: ^4.1.0 + json-stable-stringify-without-jsonify: ^1.0.1 + levn: ^0.4.1 + lodash.merge: ^4.6.2 + minimatch: ^3.1.2 + natural-compare: ^1.4.0 + optionator: ^0.9.3 + strip-ansi: ^6.0.1 + text-table: ^0.2.0 + bin: + eslint: bin/eslint.js + checksum: 2da808655c7aa4b33f8970ba30d96b453c3071cc4d6cd60d367163430677e32ff186b65270816b662d29139283138bff81f28dddeb2e73265495245a316ed02c + languageName: node + linkType: hard + "espree@npm:^9.6.0, espree@npm:^9.6.1": version: 9.6.1 resolution: "espree@npm:9.6.1" @@ -5383,7 +5786,14 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1": +"heap@npm:^0.2.6": + version: 0.2.7 + resolution: "heap@npm:0.2.7" + checksum: b0f3963a799e02173f994c452921a777f2b895b710119df999736bfed7477235c2860c423d9aea18a9f3b3d065cb1114d605c208cfcb8d0ac550f97ec5d28cb0 + languageName: node + linkType: hard + +"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -8567,6 +8977,38 @@ __metadata: languageName: node linkType: hard +"react-redux@npm:^8.1.2": + version: 8.1.2 + resolution: "react-redux@npm:8.1.2" + dependencies: + "@babel/runtime": ^7.12.1 + "@types/hoist-non-react-statics": ^3.3.1 + "@types/use-sync-external-store": ^0.0.3 + hoist-non-react-statics: ^3.3.2 + react-is: ^18.0.0 + use-sync-external-store: ^1.0.0 + peerDependencies: + "@types/react": ^16.8 || ^17.0 || ^18.0 + "@types/react-dom": ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + react-native: ">=0.59" + redux: ^4 || ^5.0.0-beta.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + react-dom: + optional: true + react-native: + optional: true + redux: + optional: true + checksum: 4d5976b0f721e4148475871fcabce2fee875cc7f70f9a292f3370d63b38aa1dd474eb303c073c5555f3e69fc732f3bac05303def60304775deb28361e3f4b7cc + languageName: node + linkType: hard + "react-sortable-tree-patch-react-17@npm:^2.9.0": version: 2.9.0 resolution: "react-sortable-tree-patch-react-17@npm:2.9.0" @@ -9048,7 +9490,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.5.5": +"rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" dependencies: @@ -10309,6 +10751,15 @@ __metadata: languageName: node linkType: hard +"use-sync-external-store@npm:^1.0.0": + version: 1.2.0 + resolution: "use-sync-external-store@npm:1.2.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2"