From 30d502ff637bce778ec3ec5de86e357e61f0d68a Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Thu, 14 Apr 2022 11:41:13 +0200 Subject: fix(web/ui): Fix hotkeys support in React 18 This change fixes an issue where the library for hotkeys that we previously used does not (yet) support React 18. Instead, we switch to a simpler solution based on React Hooks which is compatible with React 18. --- opendc-web/opendc-web-ui/package-lock.json | 56 +++++++++++++++++----- opendc-web/opendc-web-ui/package.json | 2 +- .../src/components/topologies/TopologyMap.js | 27 ++++------- .../src/components/topologies/map/MapStage.js | 26 +++++----- opendc-web/opendc-web-ui/src/hotkeys.js | 6 --- 5 files changed, 70 insertions(+), 47 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/hotkeys.js (limited to 'opendc-web') diff --git a/opendc-web/opendc-web-ui/package-lock.json b/opendc-web/opendc-web-ui/package-lock.json index 4c8f4e73..03f6bcc1 100644 --- a/opendc-web/opendc-web-ui/package-lock.json +++ b/opendc-web/opendc-web-ui/package-lock.json @@ -31,7 +31,7 @@ "prop-types": "^15.7.2", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-hotkeys": "^2.0.0", + "react-hotkeys-hook": "^3.4.6", "react-konva": "^17.0.2-5", "react-query": "^3.22.0", "react-redux": "^7.2.5", @@ -2527,6 +2527,11 @@ "react-is": "^16.7.0" } }, + "node_modules/hotkeys-js": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.9.3.tgz", + "integrity": "sha512-s+f0xyvDmf6+DyrFQ2SY+eA7lbvMbjqkqi0I0SpMgnN5tZx7DeH8nsWhkJR4KEq3pxDPHJppDUhdt1rZFW5LeQ==" + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -3635,15 +3640,16 @@ "react": ">=0.14.0" } }, - "node_modules/react-hotkeys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", - "integrity": "sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q==", + "node_modules/react-hotkeys-hook": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.6.tgz", + "integrity": "sha512-SiGKHnauaAQglRA7qeiW5LTa0KoT2ssv8YGYKZQoM3P9v5JFEHJdXOSFml1N6K86oKQ8dLCLlxqBqGlSJWGmxQ==", "dependencies": { - "prop-types": "^15.6.1" + "hotkeys-js": "3.9.3" }, "peerDependencies": { - "react": ">= 0.14.0" + "react": ">=16.8.1", + "react-dom": ">=16.8.1" } }, "node_modules/react-is": { @@ -4370,6 +4376,20 @@ "node": ">= 10" } }, + "node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", @@ -6279,6 +6299,11 @@ "react-is": "^16.7.0" } }, + "hotkeys-js": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.9.3.tgz", + "integrity": "sha512-s+f0xyvDmf6+DyrFQ2SY+eA7lbvMbjqkqi0I0SpMgnN5tZx7DeH8nsWhkJR4KEq3pxDPHJppDUhdt1rZFW5LeQ==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -7000,12 +7025,12 @@ "prop-types-extra": "^1.1.0" } }, - "react-hotkeys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", - "integrity": "sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q==", + "react-hotkeys-hook": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.6.tgz", + "integrity": "sha512-SiGKHnauaAQglRA7qeiW5LTa0KoT2ssv8YGYKZQoM3P9v5JFEHJdXOSFml1N6K86oKQ8dLCLlxqBqGlSJWGmxQ==", "requires": { - "prop-types": "^15.6.1" + "hotkeys-js": "3.9.3" } }, "react-is": { @@ -7477,6 +7502,13 @@ "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.1.0.tgz", "integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==" }, + "typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true, + "peer": true + }, "typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", diff --git a/opendc-web/opendc-web-ui/package.json b/opendc-web/opendc-web-ui/package.json index b3684d67..6bead45a 100644 --- a/opendc-web/opendc-web-ui/package.json +++ b/opendc-web/opendc-web-ui/package.json @@ -39,7 +39,7 @@ "prop-types": "^15.7.2", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-hotkeys": "^2.0.0", + "react-hotkeys-hook": "^3.4.6", "react-konva": "^17.0.2-5", "react-query": "^3.22.0", "react-redux": "^7.2.5", diff --git a/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js b/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js index 2f27749f..47235c7e 100644 --- a/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js +++ b/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js @@ -20,7 +20,7 @@ * SOFTWARE. */ -import React, { useState } from 'react' +import React, { useState, useRef } from 'react' import { Bullseye, Drawer, @@ -31,8 +31,6 @@ import { Spinner, Title, } from '@patternfly/react-core' -import { configure, HotKeys } from 'react-hotkeys' -import { KeymapConfiguration } from '../../hotkeys' import MapStage from './map/MapStage' import Collapse from './map/controls/Collapse' import { useSelector } from 'react-redux' @@ -45,10 +43,7 @@ function TopologyMap() { const [isExpanded, setExpanded] = useState(true) const panelContent = setExpanded(false)} /> - // Make sure that holding down a key will generate repeated events - configure({ - ignoreRepeatedEventsWhenKeyHeldDown: false, - }) + const hotkeysRef = useRef() return topologyIsLoading ? ( @@ -60,16 +55,14 @@ function TopologyMap() { ) : ( - - - - - - setExpanded(true)} /> - - - - + + + + + setExpanded(true)} /> + + + ) } diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js b/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js index d8735cf1..7b96f548 100644 --- a/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js +++ b/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js @@ -1,5 +1,6 @@ import React, { useRef, useState, useContext } from 'react' -import { HotKeys } from 'react-hotkeys' +import PropTypes from 'prop-types' +import { useHotkeys } from 'react-hotkeys-hook' import { Stage } from 'react-konva' import { MAP_MAX_SCALE, MAP_MIN_SCALE, MAP_MOVE_PIXELS_PER_EVENT, MAP_SCALE_PER_EVENT } from './MapConstants' import { ReactReduxContext } from 'react-redux' @@ -11,10 +12,10 @@ import ObjectHoverLayer from './layers/ObjectHoverLayer' import ScaleIndicator from './controls/ScaleIndicator' import Toolbar from './controls/Toolbar' -function MapStage() { +function MapStage({ hotkeysRef }) { const reduxContext = useContext(ReactReduxContext) - const { ref, width = 100, height = 100 } = useResizeObserver() const stageRef = useRef(null) + const { width = 100, height = 100 } = useResizeObserver({ ref: stageRef.current?.attrs?.container }) const [[x, y], setPos] = useState([0, 0]) const [scale, setScale] = useState(1) @@ -48,16 +49,15 @@ function MapStage() { download.click() } - const handlers = { - MOVE_LEFT: () => moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0), - MOVE_RIGHT: () => moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0), - MOVE_UP: () => moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT), - MOVE_DOWN: () => moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT), - } + useHotkeys('left, a', () => moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0), { element: hotkeysRef.current }) + useHotkeys('right, d', () => moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0), { element: hotkeysRef.current }) + useHotkeys('up, w', () => moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT), { element: hotkeysRef.current }) + useHotkeys('down, s', () => moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT), { element: hotkeysRef.current }) return ( - + <> - + ) } +MapStage.propTypes = { + hotkeysRef: PropTypes.object.isRequired, +} + export default MapStage diff --git a/opendc-web/opendc-web-ui/src/hotkeys.js b/opendc-web/opendc-web-ui/src/hotkeys.js deleted file mode 100644 index 1c4d2621..00000000 --- a/opendc-web/opendc-web-ui/src/hotkeys.js +++ /dev/null @@ -1,6 +0,0 @@ -export const KeymapConfiguration = { - MOVE_LEFT: ['a', 'left'], - MOVE_RIGHT: ['d', 'right'], - MOVE_UP: ['w', 'up'], - MOVE_DOWN: ['s', 'down'], -} -- cgit v1.2.3