From 8779baef3229654fa206d39d155de49effc2528a Mon Sep 17 00:00:00 2001 From: Arnei Date: Fri, 12 May 2023 11:36:56 +0200 Subject: [PATCH 01/16] Update to React 18 Bumps React version to 18, and includes all the necessary changes that React 18 demands. Does not yet include the switch to the new rendering API. This is just about getting everything to work with React 18. --- package-lock.json | 424 +++++---------------------------- package.json | 14 +- src/main/SubtitleTimeline.tsx | 14 +- src/main/SubtitleVideoArea.tsx | 71 +++--- src/main/WorkflowSelection.tsx | 34 ++- 5 files changed, 124 insertions(+), 433 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76b9a1c38..a95f88e0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,13 +18,12 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@iarna/toml": "^2.2.5", "@mui/material": "^5.12.2", - "@mui/styles": "^5.12.0", "@mui/x-date-pickers": "^5.0.20", "@reduxjs/toolkit": "^1.9.5", "@testing-library/jest-dom": "^5.16.5", "@types/iarna__toml": "^2.0.2", - "@types/react": "^17.0.45", - "@types/react-dom": "^18.0.3", + "@types/react": "^18.2.6", + "@types/react-dom": "^18.2.4", "customize-cra": "^1.0.0", "deepmerge": "^4.3.1", "emotion-normalize": "^11.0.1", @@ -33,18 +32,17 @@ "i18next-browser-languagedetector": "^7.0.1", "lodash": "^4.17.21", "luxon": "^3.3.0", - "mui-rff": "^5.3.2", - "react": "^17.0.2", + "mui-rff": "^6.1.4", + "react": "^18.2.0", "react-app-rewired": "^2.2.1", "react-beforeunload": "^2.5.3", "react-device-detect": "^2.2.3", - "react-dom": "^17.0.2", + "react-dom": "^18.2.0", "react-draggable": "^4.4.5", "react-final-form": "^6.5.9", - "react-final-form-listeners": "^1.0.3", "react-hotkeys": "^2.0.0", "react-i18next": "^12.2.2", - "react-indiana-drag-scroll": "^2.1.0", + "react-indiana-drag-scroll": "^2.2.0", "react-player": "git+https://arnei@github.com/Arnei/react-player.git#20fe6c061cf7d71d33d764b4a51c9b9bbb614bf6", "react-redux": "^8.0.5", "react-resizable": "^3.0.5", @@ -4087,46 +4085,6 @@ } } }, - "node_modules/@mui/styles": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/styles/-/styles-5.12.0.tgz", - "integrity": "sha512-X7obkgZTd9X+7igqwKKe8pEncyXYdUCNmyJfHruV9TSc6LThoI29OYs6hkN6n+7ueNli+YDKdZ+TCoC1GpJuOw==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "@emotion/hash": "^0.9.0", - "@mui/private-theming": "^5.12.0", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.12.0", - "clsx": "^1.2.1", - "csstype": "^3.1.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.10.0", - "jss-plugin-camel-case": "^10.10.0", - "jss-plugin-default-unit": "^10.10.0", - "jss-plugin-global": "^10.10.0", - "jss-plugin-nested": "^10.10.0", - "jss-plugin-props-sort": "^10.10.0", - "jss-plugin-rule-value-function": "^10.10.0", - "jss-plugin-vendor-prefixer": "^10.10.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@types/react": "^17.0.0", - "react": "^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/system": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.12.1.tgz", @@ -5156,9 +5114,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "17.0.50", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", - "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.6.tgz", + "integrity": "sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -5175,9 +5133,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", - "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", + "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", "dependencies": { "@types/react": "*" } @@ -7356,15 +7314,6 @@ "node": ">=0.10.0" } }, - "node_modules/css-vendor": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", - "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", - "dependencies": { - "@babel/runtime": "^7.8.3", - "is-in-browser": "^1.0.2" - } - }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -9975,11 +9924,6 @@ "node": ">=10.17.0" } }, - "node_modules/hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" - }, "node_modules/i18next": { "version": "22.0.4", "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.0.4.tgz", @@ -10272,11 +10216,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-in-browser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" - }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -14019,88 +13958,6 @@ "node": ">=0.10.0" } }, - "node_modules/jss": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", - "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "csstype": "^3.0.2", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/jss" - } - }, - "node_modules/jss-plugin-camel-case": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", - "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "hyphenate-style-name": "^1.0.3", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-default-unit": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", - "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-global": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", - "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-nested": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", - "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "node_modules/jss-plugin-props-sort": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", - "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-rule-value-function": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", - "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "node_modules/jss-plugin-vendor-prefixer": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", - "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "css-vendor": "^2.0.8", - "jss": "10.10.0" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -14553,26 +14410,26 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mui-rff": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/mui-rff/-/mui-rff-5.3.2.tgz", - "integrity": "sha512-cTWZ2HiMviK9+BPa3AzJHWM8V3RpnHgoEIdEbYpYjAD5QhSqMnL2yaZZ6P9/Q+61wQccH7ZzjE/qVnSwEMhWNA==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/mui-rff/-/mui-rff-6.1.4.tgz", + "integrity": "sha512-9en2EHHhzuaX39xrCcpKLgyJ5cPVNmZlyhY4ZZxHXFPI+NdJa2DF2wTOOP5SE58qhC3jZzza81HJpi5aqqPFYQ==", "engines": { "node": ">=10" }, "optionalDependencies": { - "@date-io/core": "^2.11.0", - "@date-io/date-fns": "^2.11.0", - "date-fns": "^2.25.0", + "@date-io/core": "^2.16.0", + "@date-io/date-fns": "^2.16.0", + "date-fns": "^2.29.3", "yup": "^0.32.11" }, "peerDependencies": { - "@emotion/react": "^11.9.0", - "@emotion/styled": "^11.8.1", - "@mui/material": "^5.6.1", - "@mui/styles": "^5.6.1", - "@mui/x-date-pickers": "^5.0.0-alpha.0", + "@emotion/react": "^11.10.4", + "@emotion/styled": "^11.10.4", + "@mui/material": "^5.10.5", + "@mui/system": "^5.10.5", + "@mui/x-date-pickers": "^5.0.1", "final-form": ">=4.19.1 < 5", - "react": ">=16", + "react": ">=18", "react-final-form": "^6.5.9" } }, @@ -16629,12 +16486,11 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -16818,16 +16674,15 @@ } }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.0" }, "peerDependencies": { - "react": "17.0.2" + "react": "^18.2.0" } }, "node_modules/react-draggable": { @@ -16869,20 +16724,6 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/react-final-form-listeners": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/react-final-form-listeners/-/react-final-form-listeners-1.0.3.tgz", - "integrity": "sha512-OrdCNxSS4JQS/EXD+R530kZKFqaPfa+WcXPgVro/h4BpaBDF/Ja+BtHyCzDezCIb5rWaGGdOJIj+tN2YdtvrXg==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "peerDependencies": { - "final-form": ">=4.0.0", - "prop-types": "^15.6.0", - "react": "^15.3.0 || ^16.0.0 || ^17.0.0", - "react-final-form": ">=3.0.0" - } - }, "node_modules/react-hotkeys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", @@ -17716,12 +17557,11 @@ } }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { @@ -18684,11 +18524,6 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -22848,30 +22683,6 @@ "prop-types": "^15.8.1" } }, - "@mui/styles": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/styles/-/styles-5.12.0.tgz", - "integrity": "sha512-X7obkgZTd9X+7igqwKKe8pEncyXYdUCNmyJfHruV9TSc6LThoI29OYs6hkN6n+7ueNli+YDKdZ+TCoC1GpJuOw==", - "requires": { - "@babel/runtime": "^7.21.0", - "@emotion/hash": "^0.9.0", - "@mui/private-theming": "^5.12.0", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.12.0", - "clsx": "^1.2.1", - "csstype": "^3.1.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.10.0", - "jss-plugin-camel-case": "^10.10.0", - "jss-plugin-default-unit": "^10.10.0", - "jss-plugin-global": "^10.10.0", - "jss-plugin-nested": "^10.10.0", - "jss-plugin-props-sort": "^10.10.0", - "jss-plugin-rule-value-function": "^10.10.0", - "jss-plugin-vendor-prefixer": "^10.10.0", - "prop-types": "^15.8.1" - } - }, "@mui/system": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.12.1.tgz", @@ -23584,9 +23395,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/react": { - "version": "17.0.50", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", - "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.6.tgz", + "integrity": "sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -23603,9 +23414,9 @@ } }, "@types/react-dom": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", - "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", + "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", "requires": { "@types/react": "*" } @@ -25221,15 +25032,6 @@ } } }, - "css-vendor": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", - "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", - "requires": { - "@babel/runtime": "^7.8.3", - "is-in-browser": "^1.0.2" - } - }, "css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -27132,11 +26934,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, - "hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" - }, "i18next": { "version": "22.0.4", "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.0.4.tgz", @@ -27326,11 +27123,6 @@ "is-extglob": "^2.1.1" } }, - "is-in-browser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" - }, "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -30124,84 +29916,6 @@ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==" }, - "jss": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", - "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^3.0.2", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - } - }, - "jss-plugin-camel-case": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", - "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", - "requires": { - "@babel/runtime": "^7.3.1", - "hyphenate-style-name": "^1.0.3", - "jss": "10.10.0" - } - }, - "jss-plugin-default-unit": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", - "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "jss-plugin-global": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", - "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "jss-plugin-nested": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", - "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "jss-plugin-props-sort": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", - "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "jss-plugin-rule-value-function": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", - "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "jss-plugin-vendor-prefixer": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", - "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", - "requires": { - "@babel/runtime": "^7.3.1", - "css-vendor": "^2.0.8", - "jss": "10.10.0" - } - }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -30542,13 +30256,13 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mui-rff": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/mui-rff/-/mui-rff-5.3.2.tgz", - "integrity": "sha512-cTWZ2HiMviK9+BPa3AzJHWM8V3RpnHgoEIdEbYpYjAD5QhSqMnL2yaZZ6P9/Q+61wQccH7ZzjE/qVnSwEMhWNA==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/mui-rff/-/mui-rff-6.1.4.tgz", + "integrity": "sha512-9en2EHHhzuaX39xrCcpKLgyJ5cPVNmZlyhY4ZZxHXFPI+NdJa2DF2wTOOP5SE58qhC3jZzza81HJpi5aqqPFYQ==", "requires": { - "@date-io/core": "^2.11.0", - "@date-io/date-fns": "^2.11.0", - "date-fns": "^2.25.0", + "@date-io/core": "^2.16.0", + "@date-io/date-fns": "^2.16.0", + "date-fns": "^2.29.3", "yup": "^0.32.11" } }, @@ -31841,12 +31555,11 @@ } }, "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "react-app-polyfill": { @@ -31981,13 +31694,12 @@ } }, "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.0" } }, "react-draggable": { @@ -32017,14 +31729,6 @@ "@babel/runtime": "^7.15.4" } }, - "react-final-form-listeners": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/react-final-form-listeners/-/react-final-form-listeners-1.0.3.tgz", - "integrity": "sha512-OrdCNxSS4JQS/EXD+R530kZKFqaPfa+WcXPgVro/h4BpaBDF/Ja+BtHyCzDezCIb5rWaGGdOJIj+tN2YdtvrXg==", - "requires": { - "@babel/runtime": "^7.12.5" - } - }, "react-hotkeys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", @@ -32595,12 +32299,11 @@ } }, "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "schema-utils": { @@ -33355,11 +33058,6 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", diff --git a/package.json b/package.json index 96b39df30..1a550d07a 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,12 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@iarna/toml": "^2.2.5", "@mui/material": "^5.12.2", - "@mui/styles": "^5.12.0", "@mui/x-date-pickers": "^5.0.20", "@reduxjs/toolkit": "^1.9.5", "@testing-library/jest-dom": "^5.16.5", "@types/iarna__toml": "^2.0.2", - "@types/react": "^17.0.45", - "@types/react-dom": "^18.0.3", + "@types/react": "^18.2.6", + "@types/react-dom": "^18.2.4", "customize-cra": "^1.0.0", "deepmerge": "^4.3.1", "emotion-normalize": "^11.0.1", @@ -28,18 +27,17 @@ "i18next-browser-languagedetector": "^7.0.1", "lodash": "^4.17.21", "luxon": "^3.3.0", - "mui-rff": "^5.3.2", - "react": "^17.0.2", + "mui-rff": "^6.1.4", + "react": "^18.2.0", "react-app-rewired": "^2.2.1", "react-beforeunload": "^2.5.3", "react-device-detect": "^2.2.3", - "react-dom": "^17.0.2", + "react-dom": "^18.2.0", "react-draggable": "^4.4.5", "react-final-form": "^6.5.9", - "react-final-form-listeners": "^1.0.3", "react-hotkeys": "^2.0.0", "react-i18next": "^12.2.2", - "react-indiana-drag-scroll": "^2.1.0", + "react-indiana-drag-scroll": "^2.2.0", "react-player": "git+https://arnei@github.com/Arnei/react-player.git#20fe6c061cf7d71d33d764b4a51c9b9bbb614bf6", "react-redux": "^8.0.5", "react-resizable": "^3.0.5", diff --git a/src/main/SubtitleTimeline.tsx b/src/main/SubtitleTimeline.tsx index dee38b875..f2d57182c 100644 --- a/src/main/SubtitleTimeline.tsx +++ b/src/main/SubtitleTimeline.tsx @@ -40,7 +40,7 @@ import { t } from "i18next"; const currentlyAt = useSelector(selectCurrentlyAt) const { ref, width = 1, } = useResizeObserver(); - const refTop = useRef(null); + const refTop = useRef(null); const { ref: refMini, width: widthMiniTimeline = 1, } = useResizeObserver(); const timelineCutoutInMs = 10000 // How much of the timeline should be visible in milliseconds. Aka a specific zoom level @@ -62,8 +62,8 @@ import { t } from "i18next"; // Apply horizonal scrolling when scrolled from somewhere else useEffect(() => { if (currentlyAt !== undefined && refTop.current) { - const scrollLeftMax = (refTop.current.getElement().scrollWidth - refTop.current.getElement().clientWidth) - refTop.current.getElement().scrollTo(Math.round((currentlyAt / duration) * scrollLeftMax), 0) + const scrollLeftMax = (refTop.current.scrollWidth - refTop.current.clientWidth) + refTop.current.scrollTo(Math.round((currentlyAt / duration) * scrollLeftMax), 0) } }, [currentlyAt, duration, width]); @@ -83,8 +83,8 @@ import { t } from "i18next"; const onEndScroll = (e: ScrollEvent) => { // If scrolled by user if (!e.external && refTop && refTop.current) { - const offsetX = refTop.current.getElement().scrollLeft - const scrollLeftMax = (refTop.current.getElement().scrollWidth - refTop.current.getElement().clientWidth) + const offsetX = refTop.current.scrollLeft + const scrollLeftMax = (refTop.current.scrollWidth - refTop.current.clientWidth) dispatch(setCurrentlyAt((offsetX / scrollLeftMax) * (duration))) } } @@ -97,14 +97,14 @@ import { t } from "i18next"; position: 'absolute', width: '2px', height: '190px', - ...(refTop.current) && {left: (refTop.current.getElement().clientWidth / 2)}, + ...(refTop.current) && {left: (refTop.current.clientWidth / 2)}, top: '10px', background: `${theme.text}`, zIndex: 100, }} /> {/* Scrollable timeline container. Has width of parent*/} - = () => { return(
- (a.push(o.flavor), a), [])} changeFlavorcallback={setSelectedFlavor} defaultFlavor={selectedFlavor} - /> + />} {/* TODO: Make preview mode work or remove it */} = () => { const VideoSelectDropdown : React.FC<{ flavors: Flavor[], changeFlavorcallback: React.Dispatch>, - defaultFlavor: Flavor | undefined + defaultFlavor: Flavor }> = ({ flavors, changeFlavorcallback, @@ -183,50 +181,37 @@ const VideoSelectDropdown : React.FC<{ } // Data to populate the dropdown with - const selectData = () => { - const data = [] - for (let flavor of flavors) { - // We have to deconstruct the flavor object for the value as well and put it back together - data.push({label: getFlavorLabel(flavor), value: stringifyFlavor(flavor)}) - } - return data + const data: {label: string, value: string}[] = [] + for (let flavor of flavors) { + // We have to deconstruct the flavor object for the value as well and put it back together + data.push({label: getFlavorLabel(flavor), value: stringifyFlavor(flavor)}) } - const onSubmit = () => {} - - const subtitleAddFormStyle = css({ width: '100%', }); return ( -
( - { - handleSubmit(event) - }} css={subtitleAddFormStyle}> - - - value === stringifyFlavor(defaultFlavor))} + onChange={ + (newValue) => { + if (newValue) { + console.log(newValue) // Put flavor back together - const newFlavor: Flavor = {type: value.split("/")[0], subtype: value.split("/")[1]} + const newFlavor: Flavor = {type: newValue.value.split("/")[0], subtype: newValue.value.split("/")[1]} changeFlavorcallback(newFlavor) - }} - - - )} - /> + } + } + } + /> + ) } diff --git a/src/main/WorkflowSelection.tsx b/src/main/WorkflowSelection.tsx index 2a64ad92c..18abcdc5b 100644 --- a/src/main/WorkflowSelection.tsx +++ b/src/main/WorkflowSelection.tsx @@ -19,7 +19,6 @@ import { EmotionJSX } from "@emotion/react/types/jsx-namespace"; import './../i18n/config'; import { useTranslation } from 'react-i18next'; import { Trans } from "react-i18next"; -import { withStyles } from "@mui/styles"; import { FormControlLabel, Radio, RadioGroup } from "@mui/material"; import { selectTheme } from "../redux/themeSlice"; @@ -78,7 +77,7 @@ const WorkflowSelection : React.FC<{}> = () => { return (

{topTitle}

- {topText} + {!!topText} { hasWorkflowButtons && ); +const WorkflowSelectRadio: React.FC = () => { + + const style = css({ + root: { + alignSelf: 'start', + color: 'grey', + "&$checked": { + color: 'grey' + } + }, + }) + + return ( + + ) +} + export default WorkflowSelection; From 170e2150ee5680e0064ecb70406f1e33b02d526b Mon Sep 17 00:00:00 2001 From: Arnei Date: Mon, 15 May 2023 10:35:52 +0200 Subject: [PATCH 02/16] Update React rendering pipeline to new standard React 18 brings with it a new and improved rendering method. This commit activates it. It also removes a workaround pertaining to react-hotkeys that is not used anymore anyway? --- src/index.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 555d5ed5c..7479aff11 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import './index.css'; import App from './App'; import { Provider } from 'react-redux' @@ -10,9 +10,12 @@ import { sleep } from './util/utilityFunctions' import { LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import { GlobalHotKeys } from 'react-hotkeys'; +const container = document.getElementById('root') +if (!container) throw new Error('Failed to find the root element'); +const root = ReactDOMClient.createRoot(container); + // Load config here // Load the rest of the application and try to fetch the settings file from the // server. @@ -22,24 +25,20 @@ const initialize = Promise.race([ ]); const render = (body: JSX.Element) => { - ReactDOM.render(body, document.getElementById('root')); + root.render(body); }; initialize.then( () => { - ReactDOM.render( + root.render( - {/* Workaround for getApplicationKeyMap based on https://github.com/greena13/react-hotkeys/issues/228 */} - - - , - document.getElementById('root') + ); }, From 88d312a936d034874d3cd9b2cd79dd948fe721de Mon Sep 17 00:00:00 2001 From: Arnei Date: Fri, 1 Sep 2023 10:33:29 +0200 Subject: [PATCH 03/16] Fix subtitle view crashing the editor Fixes a bug causing infinite rerenders in the subtitle view. Limiting how often we set video aspect ratios in redux seems to fix the issue. --- src/main/Video.tsx | 9 ++++++--- src/redux/videoSlice.ts | 8 +++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/Video.tsx b/src/main/Video.tsx index 161f4ce10..d42199cb1 100644 --- a/src/main/Video.tsx +++ b/src/main/Video.tsx @@ -266,7 +266,7 @@ export const VideoPlayer = React.forwardRef( } useEffect(() => { - // Seek if the position in the video got changed externally + // Seek if the position in the video got changed externally if (!isPlaying && ref.current && ready) { ref.current.seekTo(currentlyAt, "seconds") } @@ -278,11 +278,14 @@ export const VideoPlayer = React.forwardRef( ref.current.seekTo(currentlyAt, "seconds") dispatch(setClickTriggered(false)) } - if (!isAspectRatioUpdated && ready) { // if (!isAspectRatioUpdated && ref.current && ready) { + }) + + useEffect(() => { + if (!isAspectRatioUpdated && ready) { // Update the store with video dimensions for rendering purposes updateAspectRatio(); } - }) + }, [isAspectRatioUpdated, ready]) // Callback specifically for the subtitle editor view // When changing urls while the player is playing, don't reset to 0 diff --git a/src/redux/videoSlice.ts b/src/redux/videoSlice.ts index 4bb612a3d..bffadd8f1 100644 --- a/src/redux/videoSlice.ts +++ b/src/redux/videoSlice.ts @@ -321,8 +321,14 @@ const skipDeletedSegments = (state: video) => { * TODO: Improve calculation to handle multiple rows of videos */ export const calculateTotalAspectRatio = (aspectRatios: video["aspectRatios"]) => { - const minHeight = Math.min(...aspectRatios.map(o => o.height)) + let minHeight = Math.min(...aspectRatios.map(o => o.height)) let minWidth = Math.min(...aspectRatios.map(o => o.width)) + // Getting the aspect ratios of every video can take several seconds + // So we assume a default resolution until then + if (!minHeight || !minWidth) { + minHeight = 720 + minWidth = 1280 + } minWidth *= aspectRatios.length return Math.min((minHeight / minWidth) * 100, (9 / 32) * 100) } From 9d8d68e44e9ebb95670630bf5ccf5dd152b0056d Mon Sep 17 00:00:00 2001 From: Arnei Date: Mon, 4 Sep 2023 14:22:47 +0200 Subject: [PATCH 04/16] Replace react-hotkeys with react-hotkeys-hook react-hotkeys did not work properly anymore with the upgrade to React 18. Furthermore, it has been unmaintained for several years at this point. Therefore, switching to a newer, maintained library seems a necessity. This commit introduces react-hotkeys-hook to take over hotkeys functionality. To a user everything should work like before and everything it should look like nothing changed (except for maybe the order on the overview page, but that never followed any rhyme or reason in the first place). --- package-lock.json | 28 ++-- package.json | 2 +- src/config.ts | 20 --- src/globalKeys.ts | 231 ++++++++++++-------------------- src/main/Body.tsx | 1 - src/main/CuttingActions.tsx | 96 +++++++------ src/main/KeyboardControls.tsx | 57 ++++---- src/main/SubtitleListEditor.tsx | 195 ++++++++++++++------------- src/main/SubtitleTimeline.tsx | 48 +++---- src/main/Timeline.tsx | 62 ++++----- src/main/Video.tsx | 35 ++--- 11 files changed, 333 insertions(+), 442 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ae113602..6ea2efa3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "react-dom": "^18.2.0", "react-draggable": "^4.4.5", "react-final-form": "^6.5.9", - "react-hotkeys": "^2.0.0", + "react-hotkeys-hook": "^4.4.1", "react-i18next": "^13.1.2", "react-indiana-drag-scroll": "^2.2.0", "react-player": "git+https://arnei@github.com/Arnei/react-player.git#20fe6c061cf7d71d33d764b4a51c9b9bbb614bf6", @@ -17212,15 +17212,13 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.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==", - "dependencies": { - "prop-types": "^15.6.1" - }, + "node_modules/react-hotkeys-hook": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz", + "integrity": "sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==", "peerDependencies": { - "react": ">= 0.14.0" + "react": ">=16.8.1", + "react-dom": ">=16.8.1" } }, "node_modules/react-i18next": { @@ -33897,13 +33895,11 @@ "@babel/runtime": "^7.15.4" } }, - "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==", - "requires": { - "prop-types": "^15.6.1" - } + "react-hotkeys-hook": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz", + "integrity": "sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==", + "requires": {} }, "react-i18next": { "version": "13.1.2", diff --git a/package.json b/package.json index 80de13bba..7f95d7cd7 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "react-dom": "^18.2.0", "react-draggable": "^4.4.5", "react-final-form": "^6.5.9", - "react-hotkeys": "^2.0.0", + "react-hotkeys-hook": "^4.4.1", "react-i18next": "^13.1.2", "react-indiana-drag-scroll": "^2.2.0", "react-player": "git+https://arnei@github.com/Arnei/react-player.git#20fe6c061cf7d71d33d764b4a51c9b9bbb614bf6", diff --git a/src/config.ts b/src/config.ts index 4c5b3c9ae..c44c2381b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,7 +9,6 @@ */ import parseToml from '@iarna/toml/parse-string'; import deepmerge from 'deepmerge'; -import { configure } from 'react-hotkeys'; import { Flavor } from './types'; /** @@ -145,25 +144,6 @@ export const init = async () => { // Prepare local setting to avoid complicated checks later settings.opencast.local = settings.opencast.local && settings.opencast.url === window.location.origin; - - // Configure hotkeys - configure({ - ignoreTags: [], // Do not ignore hotkeys when focused on a textarea, input, select - ignoreEventsCondition: (e: any) => { - // Ignore hotkeys when focused on a textarea, input, select IF that hotkey is expected to perform - // a certain function in that element that is more important than any hotkey function - // (e.g. you need "Space" in a textarea to create whitespaces, not play/pause videos) - if (e.target && e.target.tagName) { - const tagname = e.target.tagName.toLowerCase() - if ((tagname === "textarea" || tagname === "input" || tagname === "select") - && (!e.altKey && !e.ctrlKey) - && (e.code === "Space" || e.code === "ArrowLeft" || e.code === "ArrowRight" || e.code === "ArrowUp" || e.code === "ArrowDown")) { - return true - } - } - return false - }, - }) }; /** diff --git a/src/globalKeys.ts b/src/globalKeys.ts index c0dd3e564..f4820af41 100644 --- a/src/globalKeys.ts +++ b/src/globalKeys.ts @@ -1,4 +1,3 @@ -import { ApplicationKeyMap, ExtendedKeyMapOptions, KeyMapOptions, MouseTrapKeySequence } from 'react-hotkeys'; /** * Contains mappings for special keyboard controls, beyond what is usually expected of a webpage * Learn more about keymaps at https://github.com/greena13/react-hotkeys#defining-key-maps (12.03.2021) @@ -8,7 +7,6 @@ import { ApplicationKeyMap, ExtendedKeyMapOptions, KeyMapOptions, MouseTrapKeySe * * If you add a new keyMap, be sure to add it to the getAllHotkeys function */ -import { KeyMap } from "react-hotkeys"; import { isMacOs } from 'react-device-detect'; // Groups for displaying hotkeys in the overview page @@ -25,159 +23,108 @@ const rewriteKeys = (key: string) => { if (isMacOs) { newKey = newKey.replace("Alt", "Option") } + newKey = isMacOs ? newKey.replace("Mod", "Command") : newKey.replace("Mod", "Control") return newKey } -/** - * (Semi-) global map for video player controls - */ -export const videoPlayerKeyMap: KeyMap = { - preview: { - name: "video.previewButton", - sequence: rewriteKeys("Control+Alt+p"), - action: "keydown", - group: groupVideoPlayer, - }, - play: { - name: "keyboardControls.videoPlayButton", - sequence: rewriteKeys("Space"), - sequences: [rewriteKeys("Control+Alt+Space"), "Space"], - action: "keydown", - group: groupVideoPlayer, - }, +export const getGroupName = (groupName: string) => { + switch (groupName) { + case "videoPlayer": + return groupVideoPlayer + break + case "cutting": + return groupCuttingView + break + case "timeline": + return groupCuttingViewScrubber + break + case "subtitleList": + return groupSubtitleList + break + } } -/** - * (Semi-) global map for the buttons in the cutting view - */ -export const cuttingKeyMap: KeyMap = { - cut: { - name: "cuttingActions.cut-button", - sequence: rewriteKeys("Control+Alt+c"), - action: "keydown", - group: groupCuttingView, - }, - delete: { - name: "cuttingActions.delete-button", - sequence: rewriteKeys("Control+Alt+d"), - action: "keydown", - group: groupCuttingView, - }, - mergeLeft: { - name: "cuttingActions.mergeLeft-button", - sequence: rewriteKeys("Control+Alt+n"), - action: "keydown", - group: groupCuttingView, - }, - mergeRight: { - name: "cuttingActions.mergeRight-button", - sequence: rewriteKeys("Control+Alt+m"), - action: "keydown", - group: groupCuttingView, - }, +export interface KeyMapp { + [property: string]: KeyGroupp } -/** - * (Semi-) global map for moving the scrubber - */ -export const scrubberKeyMap: KeyMap = { - left: { - name: "keyboardControls.scrubberLeft", - // Typescript requires 'sequence' even though there is 'sequences, but it doesn't do anything? - sequence: rewriteKeys("Control+Alt+j"), - sequences: [rewriteKeys("Control+Alt+j"), "Left"], - action: "keydown", - group: groupCuttingViewScrubber, - }, - right: { - name: "keyboardControls.scrubberRight", - // Typescript requires 'sequence' even though there is 'sequences, but it doesn't do anything? - sequence: rewriteKeys("Control+Alt+l"), - sequences: [rewriteKeys("Control+Alt+l"), "Right"], - action: "keydown", - group: groupCuttingViewScrubber, - }, - increase: { - name: "keyboardControls.scrubberIncrease", - // Typescript requires 'sequence' even though there is 'sequences, but it doesn't do anything? - sequence: rewriteKeys("Control+Alt+i"), - sequences: [rewriteKeys("Control+Alt+i"), "Up"], - action: "keydown", - group: groupCuttingViewScrubber, - }, - decrease: { - name: "keyboardControls.scrubberDecrease", - // Typescript requires 'sequence' even though there is 'sequences, but it doesn't do anything? - sequence: rewriteKeys("Control+Alt+k"), - sequences: [rewriteKeys("Control+Alt+k"), "Down"], - action: "keydown", - group: groupCuttingViewScrubber, - }, +export interface KeyGroupp { + [property: string]: Keyy } -export const subtitleListKeyMap: KeyMap = { - addAbove: { - name: "subtitleList.addSegmentAbove", - sequence: rewriteKeys("Control+Alt+q"), - action: "keydown", - group: groupSubtitleList, - }, - addBelow: { - name: "subtitleList.addSegmentBelow", - sequence: rewriteKeys("Control+Alt+a"), - action: "keydown", - group: groupSubtitleList, +export interface Keyy { + name: string + key: string +} + +export const KEYMAP: KeyMapp = { + videoPlayer: { + play: { + name: "keyboardControls.videoPlayButton", + key: rewriteKeys("Mod+Alt+Space, Space"), + }, + preview: { + name: "video.previewButton", + key: rewriteKeys("Mod+Alt+p"), + } }, - jumpAbove: { - name: "subtitleList.jumpToSegmentAbove", - sequence: rewriteKeys("Control+Alt+w"), - action: "keydown", - group: groupSubtitleList, + cutting: { + cut: { + name: "cuttingActions.cut-button", + key: rewriteKeys("Mod+Alt+c"), + }, + delete: { + name: "cuttingActions.delete-button", + key: rewriteKeys("Mod+Alt+d"), + }, + mergeLeft: { + name: "cuttingActions.mergeLeft-button", + key: rewriteKeys("Mod+Alt+n"), + }, + mergeRight: { + name: "cuttingActions.mergeRight-button", + key: rewriteKeys("Mod+Alt+m"), + }, }, - jumpBelow: { - name: "subtitleList.jumpToSegmentBelow", - sequence: rewriteKeys("Control+Alt+s"), - action: "keydown", - group: groupSubtitleList, + timeline: { + left: { + name: "keyboardControls.scrubberLeft", + key: rewriteKeys("Mod+Alt+j , Left"), + }, + right: { + name: "keyboardControls.scrubberRight", + key: rewriteKeys("Mod+Alt+l, Right"), + }, + increase: { + name: "keyboardControls.scrubberIncrease", + key: rewriteKeys("Mod+Alt+i, Up"), + }, + decrease: { + name: "keyboardControls.scrubberDecrease", + key: rewriteKeys("Mod+Alt+k, Down"), + }, }, - delete: { - name: "subtitleList.deleteSegment", - sequence: rewriteKeys("Control+Alt+d"), - action: "keydown", - group: groupSubtitleList, - } -} - -/** - * Combines all keyMaps into a single list of keys for KeyboardControls to display - * Placing this under the keyMaps is important, else the translation hooks won't happen - */ -export const getAllHotkeys = () => { - const allKeyMaps = [videoPlayerKeyMap, cuttingKeyMap, scrubberKeyMap, subtitleListKeyMap] - const allKeys : ApplicationKeyMap = {} - - for (const keyMap of allKeyMaps) { - for (const [key, value] of Object.entries(keyMap)) { - - // Parse sequences - let sequences : KeyMapOptions[] = [] - if ((value as ExtendedKeyMapOptions).sequences !== undefined) { - for (const sequence of (value as ExtendedKeyMapOptions).sequences) { - sequences.push({sequence: sequence as MouseTrapKeySequence, action: (value as ExtendedKeyMapOptions).action}) - } - } else { - sequences = [{sequence: (value as ExtendedKeyMapOptions).sequence, action: (value as ExtendedKeyMapOptions).action }] - } - - // Create new key - allKeys[key] = { - name: (value as ExtendedKeyMapOptions).name, - group: (value as ExtendedKeyMapOptions).group, - sequences: sequences, - } + subtitleList: { + addAbove: { + name: "subtitleList.addSegmentAbove", + key: rewriteKeys("Mod+Alt+q"), + }, + addBelow: { + name: "subtitleList.addSegmentBelow", + key: rewriteKeys("Mod+Alt+a"), + }, + jumpAbove: { + name: "subtitleList.jumpToSegmentAbove", + key: rewriteKeys("Mod+Alt+w"), + }, + jumpBelow: { + name: "subtitleList.jumpToSegmentBelow", + key: rewriteKeys("Mod+Alt+s"), + }, + delete: { + name: "subtitleList.deleteSegment", + key: rewriteKeys("Mod+Alt+d"), } } - - return allKeys } diff --git a/src/main/Body.tsx b/src/main/Body.tsx index 5daf030d1..7a07ae75b 100644 --- a/src/main/Body.tsx +++ b/src/main/Body.tsx @@ -13,7 +13,6 @@ import { selectIsEnd } from '../redux/endSlice' import { selectIsError } from "../redux/errorSlice"; import { settings } from '../config'; - const Body: React.FC = () => { const isEnd = useSelector(selectIsEnd) diff --git a/src/main/CuttingActions.tsx b/src/main/CuttingActions.tsx index 0f3629ff5..52fa46004 100644 --- a/src/main/CuttingActions.tsx +++ b/src/main/CuttingActions.tsx @@ -1,4 +1,4 @@ -import React, { SyntheticEvent } from "react"; +import React from "react"; import { basicButtonStyle, flexGapReplacementStyle } from '../cssStyles' @@ -18,13 +18,13 @@ import { useDispatch, useSelector } from 'react-redux'; import { cut, markAsDeletedOrAlive, selectIsCurrentSegmentAlive, mergeLeft, mergeRight } from '../redux/videoSlice' -import { GlobalHotKeys, KeySequence, KeyMapOptions } from "react-hotkeys"; -import { cuttingKeyMap } from "../globalKeys"; +import { KEYMAP } from "../globalKeys"; import { ActionCreatorWithoutPayload } from "@reduxjs/toolkit"; import { useTranslation } from 'react-i18next'; import { selectTheme, Theme } from "../redux/themeSlice"; import { ThemedTooltip } from "./Tooltip"; +import { useHotkeys } from "react-hotkeys-hook"; /** * Defines the different actions a user can perform while in cutting mode @@ -42,9 +42,7 @@ const CuttingActions: React.FC = () => { * @param action redux event to dispatch * @param ref Pass a reference if the clicked element should lose focus */ - const dispatchAction = (event: KeyboardEvent | SyntheticEvent, action: ActionCreatorWithoutPayload, ref: React.RefObject | undefined) => { - event.preventDefault() // Prevent page scrolling due to Space bar press - event.stopPropagation() // Prevent video playback due to Space bar press + const dispatchAction = (action: ActionCreatorWithoutPayload, ref: React.RefObject | undefined) => { dispatch(action()) // Lose focus if clicked by mouse @@ -54,12 +52,10 @@ const CuttingActions: React.FC = () => { } // Maps functions to hotkeys - const handlers = { - cut: (keyEvent?: KeyboardEvent | SyntheticEvent) => { if (keyEvent) { dispatchAction(keyEvent, cut, undefined) } }, - delete: (keyEvent?: KeyboardEvent | SyntheticEvent) => { if (keyEvent) { dispatchAction(keyEvent, markAsDeletedOrAlive, undefined) } }, - mergeLeft: (keyEvent?: KeyboardEvent | SyntheticEvent) => { if (keyEvent) { dispatchAction(keyEvent, mergeLeft, undefined) } }, - mergeRight: (keyEvent?: KeyboardEvent | SyntheticEvent) => { if (keyEvent) { dispatchAction(keyEvent, mergeRight, undefined) } }, - } + useHotkeys(KEYMAP.cutting.cut.key, () => dispatchAction(cut, undefined), {preventDefault: true}, [cut]); + useHotkeys(KEYMAP.cutting.delete.key, () => dispatchAction(markAsDeletedOrAlive, undefined), {preventDefault: true}, [markAsDeletedOrAlive]); + useHotkeys(KEYMAP.cutting.mergeLeft.key, () => dispatchAction(mergeLeft, undefined), {preventDefault: true}, [mergeLeft]); + useHotkeys(KEYMAP.cutting.mergeRight.key, () => dispatchAction(mergeRight, undefined), {preventDefault: true}, [mergeRight]); const cuttingStyle = css({ display: 'flex', @@ -75,40 +71,38 @@ const CuttingActions: React.FC = () => { }) return ( - -
-
- - - - +
+ + + + +
+
+ {/* -
-
- {/* - */} -
+ */}
- +
); }; @@ -124,7 +118,7 @@ const cuttingActionButtonStyle = (theme: Theme) => css({ interface cuttingActionsButtonInterface { iconName: IconProp, actionName: string, - actionHandler: (event: KeyboardEvent | SyntheticEvent, action: ActionCreatorWithoutPayload, ref: React.RefObject | undefined) => void, + actionHandler: (action: ActionCreatorWithoutPayload, ref: React.RefObject | undefined) => void, action: ActionCreatorWithoutPayload, tooltip: string, ariaLabelText: string, @@ -143,9 +137,9 @@ const CuttingActionsButton: React.FC = ({iconName
actionHandler(event, action, ref)} + onClick={() => actionHandler(action, ref)} onKeyDown={(event: React.KeyboardEvent) => { if (event.key === " " || event.key === "Enter") { - actionHandler(event, action, undefined) + actionHandler(action, undefined) } }} > @@ -156,9 +150,9 @@ const CuttingActionsButton: React.FC = ({iconName }; interface markAsDeleteButtonInterface { - actionHandler: (event: KeyboardEvent | SyntheticEvent, action: ActionCreatorWithoutPayload, ref: React.RefObject | undefined) => void, + actionHandler: (action: ActionCreatorWithoutPayload, ref: React.RefObject | undefined) => void, action: ActionCreatorWithoutPayload, - hotKeyName: KeySequence, + hotKeyName: string, } /** @@ -177,9 +171,9 @@ const MarkAsDeletedButton : React.FC = ({actionHand ref={ref} role="button" tabIndex={0} aria-label={t('cuttingActions.delete-restore-tooltip-aria', { hotkeyName: hotKeyName })} - onClick={(event: SyntheticEvent) => actionHandler(event, action, ref)} + onClick={() => actionHandler(action, ref)} onKeyDown={(event: React.KeyboardEvent) => { if (event.key === " " || event.key === "Enter") { - actionHandler(event, action, undefined) + actionHandler(action, undefined) } }} > diff --git a/src/main/KeyboardControls.tsx b/src/main/KeyboardControls.tsx index db8012a10..727524b9a 100644 --- a/src/main/KeyboardControls.tsx +++ b/src/main/KeyboardControls.tsx @@ -3,14 +3,13 @@ import { ParseKeys } from "i18next"; import React from "react"; -import { KeyMapDisplayOptions } from 'react-hotkeys'; import { useTranslation, Trans} from "react-i18next"; import { useSelector } from "react-redux"; import { flexGapReplacementStyle } from "../cssStyles"; -import { getAllHotkeys } from "../globalKeys"; +import { getGroupName, KEYMAP } from "../globalKeys"; import { selectTheme } from "../redux/themeSlice"; -const Group: React.FC<{name: ParseKeys, entries: KeyMapDisplayOptions[]}> = ({name, entries}) => { +const Group: React.FC<{name: ParseKeys, entries: { [key: string]: string[][] }}> = ({name, entries}) => { const { t } = useTranslation(); const theme = useSelector(selectTheme); @@ -29,14 +28,14 @@ const Group: React.FC<{name: ParseKeys, entries: KeyMapDisplayOptions[]}> = ({na return (

{t(name)}

- {entries.map((entry: KeyMapDisplayOptions, index: number) => ( - - ))} + {Object.entries(entries).map(([key, value], index) => + + )}
) } -const Entry: React.FC<{params: KeyMapDisplayOptions}> = ({params}) => { +const Entry: React.FC<{name: string, sequences: string[][] }> = ({name, sequences}) => { const { t } = useTranslation(); const theme = useSelector(selectTheme); @@ -88,10 +87,10 @@ const Entry: React.FC<{params: KeyMapDisplayOptions}> = ({params}) => { return (
-
{params.name || t("keyboardControls.missingLabel")}
- {params.sequences.map((sequence, index, arr) => ( +
{name || t("keyboardControls.missingLabel")}
+ {sequences.map((sequence, index, arr) => (
- {sequence.sequence.toString().split('+').map((singleKey, index) => ( + {sequence.map((singleKey, index) => (
{singleKey}
))}
{arr.length - 1 !== index && t("keyboardControls.sequenceSeparator")}
@@ -106,8 +105,6 @@ const KeyboardControls: React.FC = () => { const { t } = useTranslation(); - const keyMap = getAllHotkeys() - const groupsStyle = css({ display: 'flex', flexDirection: 'row' as const, @@ -117,30 +114,22 @@ const KeyboardControls: React.FC = () => { }) const render = () => { - if (keyMap && Object.keys(keyMap).length > 0) { - - const obj: Record> = {} - obj[t("keyboardControls.defaultGroupName")] = [] // For keys without a group - - // Sort by group - for (const [, value] of Object.entries(keyMap)) { - if (value.group) { - if (obj[value.group]) { - obj[value.group].push(value) - } else { - obj[value.group] = [value] - } - } else { - obj[t("keyboardControls.defaultGroupName")].push(value) - } - } + if (KEYMAP && Object.keys(KEYMAP).length > 0) { const groups: JSX.Element[] = []; - for (const key in obj) { - if (obj[key].length > 0) { - groups.push(); - } - } + Object.entries(KEYMAP).forEach(([key, value], index) => { + const entries : { [key: string]: string[][] } = {} + Object.entries(value).forEach(([, value]) => { + const sequences = value.key.split(",").map(item => item.trim()) + const lol: string[][] = [] + Object.entries(sequences).forEach(([, value]) => { + const keys = value.split("+").map(item => item.trim()) + lol.push(keys) + }) + entries[value.name] = lol + }) + groups.push() + }) return (
diff --git a/src/main/SubtitleListEditor.tsx b/src/main/SubtitleListEditor.tsx index c1d3922df..1343e18e7 100644 --- a/src/main/SubtitleListEditor.tsx +++ b/src/main/SubtitleListEditor.tsx @@ -4,11 +4,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { memoize } from "lodash" import React, { useRef } from "react" import { useEffect, useState } from "react" -import { HotKeys } from "react-hotkeys" import { useTranslation } from "react-i18next" import { shallowEqual, useDispatch, useSelector } from "react-redux" import { basicButtonStyle, flexGapReplacementStyle } from "../cssStyles" -import { subtitleListKeyMap } from "../globalKeys" +import { KEYMAP } from "../globalKeys" import { addCueAtIndex, removeCue, selectFocusSegmentId, @@ -31,6 +30,7 @@ import AutoSizer from "react-virtualized-auto-sizer" import { selectTheme, selectThemeState } from "../redux/themeSlice" import { ThemedTooltip } from "./Tooltip" import { IconProp } from "@fortawesome/fontawesome-svg-core" +import { useHotkeys } from "react-hotkeys-hook" /** * Displays everything needed to edit subtitles @@ -276,23 +276,30 @@ const SubtitleListSegment = React.memo((props: subtitleListSegmentProps) => { } // Maps functions to hotkeys - const handlers = { - addAbove: () => addCueAbove(), - addBelow: () => addCueBelow(), - jumpAbove: () => { - dispatch(setFocusSegmentTriggered(true)) - dispatch(setFocusToSegmentAboveId({identifier: identifier, segmentId: cue.idInternal})) - }, - jumpBelow: () => { - dispatch(setFocusSegmentTriggered(true)) - dispatch(setFocusToSegmentBelowId({identifier: identifier, segmentId: cue.idInternal})) - }, - delete: () => { - dispatch(setFocusSegmentTriggered(true)) - dispatch(setFocusToSegmentAboveId({identifier: identifier, segmentId: cue.idInternal})) - deleteCue() - }, - } + const hotkeyRef = useHotkeys([KEYMAP.subtitleList.addAbove.key, KEYMAP.subtitleList.addBelow.key, KEYMAP.subtitleList.jumpAbove.key, KEYMAP.subtitleList.jumpBelow.key, KEYMAP.subtitleList.delete.key], + (_, handler) => { + switch (handler.keys?.join('')) { + case KEYMAP.subtitleList.addAbove.key.split('+').pop(): + addCueAbove() + break; + case KEYMAP.subtitleList.addBelow.key.split('+').pop(): + addCueBelow() + break; + case KEYMAP.subtitleList.jumpAbove.key.split('+').pop(): + dispatch(setFocusSegmentTriggered(true)) + dispatch(setFocusToSegmentAboveId({identifier: identifier, segmentId: cue.idInternal})) + break; + case KEYMAP.subtitleList.jumpBelow.key.split('+').pop(): + dispatch(setFocusSegmentTriggered(true)) + dispatch(setFocusToSegmentBelowId({identifier: identifier, segmentId: cue.idInternal})) + break; + case KEYMAP.subtitleList.delete.key.split('+').pop(): + dispatch(setFocusSegmentTriggered(true)) + dispatch(setFocusToSegmentAboveId({identifier: identifier, segmentId: cue.idInternal})) + deleteCue() + break; + } + }, { enableOnFormTags: ['input', 'select', 'textarea'] }, [identifier, cue, props.index]) const setTimeToSegmentStart = () => { dispatch(setCurrentlyAt(cue.startTime)) @@ -367,84 +374,82 @@ const SubtitleListSegment = React.memo((props: subtitleListSegmentProps) => { }) return ( - -
- -