From da70fc0946efe7e3eb81cd25923bad9543aca821 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Fri, 21 Oct 2022 08:47:42 +0200 Subject: [PATCH] Expose api for declaring keyboard shortcuts (#2139) In recent weeks we have created an api for declaring keyboard shortcuts and tested its usage in internal modules. After successfully verifying it, we are now exposing it for plugins to use. The api has also received some tweaks in the process to make it more flexible, such as allowing bound shortcuts not to appear in the documentation dialog or allowing shortcuts to explicitly allow event bubbling. --- gradle/changelog/expose_shortcuts_api.yaml | 2 + scm-ui/ui-components/src/index.ts | 1 + scm-ui/ui-components/src/table/Column.tsx | 9 ++-- scm-ui/ui-components/src/table/Table.tsx | 2 +- scm-ui/ui-components/src/table/types.ts | 1 + scm-ui/ui-shortcuts/package.json | 42 +++++++++++++++++++ scm-ui/ui-shortcuts/src/index.ts | 27 ++++++++++++ .../src}/usePauseShortcuts.ts | 1 + .../src}/useShortcut.ts | 34 +++++++++------ .../src}/useShortcutDocs.tsx | 3 +- scm-ui/ui-shortcuts/tsconfig.json | 6 +++ scm-ui/ui-webapp/package.json | 3 +- scm-ui/ui-webapp/public/locales/de/repos.json | 10 ++--- scm-ui/ui-webapp/public/locales/en/repos.json | 10 ++--- scm-ui/ui-webapp/src/containers/App.tsx | 17 +++++--- scm-ui/ui-webapp/src/containers/Index.tsx | 17 +++----- .../ui-webapp/src/containers/OmniSearch.tsx | 6 ++- scm-ui/ui-webapp/src/index.tsx | 17 ++++---- .../src/repos/containers/RepositoryRoot.tsx | 19 ++++++--- .../src/shortcuts/ShortcutDocsModal.tsx | 3 +- .../usePauseShortcutsWhenModalsActive.ts | 2 +- yarn.lock | 10 ++--- 22 files changed, 172 insertions(+), 70 deletions(-) create mode 100644 gradle/changelog/expose_shortcuts_api.yaml create mode 100644 scm-ui/ui-shortcuts/package.json create mode 100644 scm-ui/ui-shortcuts/src/index.ts rename scm-ui/{ui-webapp/src/shortcuts => ui-shortcuts/src}/usePauseShortcuts.ts (96%) rename scm-ui/{ui-webapp/src/shortcuts => ui-shortcuts/src}/useShortcut.ts (77%) rename scm-ui/{ui-webapp/src/shortcuts => ui-shortcuts/src}/useShortcutDocs.tsx (95%) create mode 100644 scm-ui/ui-shortcuts/tsconfig.json diff --git a/gradle/changelog/expose_shortcuts_api.yaml b/gradle/changelog/expose_shortcuts_api.yaml new file mode 100644 index 0000000000..c46141d630 --- /dev/null +++ b/gradle/changelog/expose_shortcuts_api.yaml @@ -0,0 +1,2 @@ +- type: changed + description: Expose api for declaring keyboard shortcuts ([#2139](https://github.com/scm-manager/scm-manager/pull/2139)) diff --git a/scm-ui/ui-components/src/index.ts b/scm-ui/ui-components/src/index.ts index 713580452e..c7f2e5ba48 100644 --- a/scm-ui/ui-components/src/index.ts +++ b/scm-ui/ui-components/src/index.ts @@ -82,6 +82,7 @@ export { default as CardColumn } from "./CardColumn"; export { default as CardColumnSmall } from "./CardColumnSmall"; export { default as CommaSeparatedList } from "./CommaSeparatedList"; export { SplitAndReplace, Replacement } from "@scm-manager/ui-text"; +export { useShortcut } from "@scm-manager/ui-shortcuts"; export { regExpPattern as changesetShortLinkRegex } from "./markdown/remarkChangesetShortLinkParser"; export * from "./markdown/PluginApi"; export * from "./devices"; diff --git a/scm-ui/ui-components/src/table/Column.tsx b/scm-ui/ui-components/src/table/Column.tsx index 488ae0b571..2e4570f2f7 100644 --- a/scm-ui/ui-components/src/table/Column.tsx +++ b/scm-ui/ui-components/src/table/Column.tsx @@ -25,17 +25,20 @@ import React, { FC, ReactNode } from "react"; import { ColumnProps } from "./types"; type Props = ColumnProps & { - children: (row: any, columnIndex: number) => ReactNode; + children: (row: any, columnIndex: number, rowIndex: number) => ReactNode; }; -const Column: FC = ({ row, columnIndex, children }) => { +const Column: FC = ({ row, columnIndex, rowIndex, children }) => { if (row === undefined) { throw new Error("missing row, use column only as child of Table"); } if (columnIndex === undefined) { throw new Error("missing row, use column only as child of Table"); } - return <>{children(row, columnIndex)}; + if (rowIndex === undefined) { + throw new Error("missing row, use column only as child of Table"); + } + return <>{children(row, columnIndex, rowIndex)}; }; export default Column; diff --git a/scm-ui/ui-components/src/table/Table.tsx b/scm-ui/ui-components/src/table/Table.tsx index 518a67b50b..4953808490 100644 --- a/scm-ui/ui-components/src/table/Table.tsx +++ b/scm-ui/ui-components/src/table/Table.tsx @@ -63,7 +63,7 @@ const Table: FC = ({ data, sortable, children, emptyMessage, className }) {React.Children.map(children, (child, columnIndex) => { const { className: columnClassName, ...childProperties } = (child as ReactElement).props; return ( - {React.cloneElement((child as ReactElement), { ...childProperties, columnIndex, row })} + {React.cloneElement((child as ReactElement), { ...childProperties, columnIndex, rowIndex, row })} ); })} diff --git a/scm-ui/ui-components/src/table/types.ts b/scm-ui/ui-components/src/table/types.ts index 7604756d03..58d4ead500 100644 --- a/scm-ui/ui-components/src/table/types.ts +++ b/scm-ui/ui-components/src/table/types.ts @@ -30,6 +30,7 @@ export type ColumnProps = { header: ReactNode; row?: any; columnIndex?: number; + rowIndex?: number; createComparator?: (props: any, columnIndex: number) => Comparator; ascendingIcon?: string; descendingIcon?: string; diff --git a/scm-ui/ui-shortcuts/package.json b/scm-ui/ui-shortcuts/package.json new file mode 100644 index 0000000000..93c76f4c7f --- /dev/null +++ b/scm-ui/ui-shortcuts/package.json @@ -0,0 +1,42 @@ +{ + "name": "@scm-manager/ui-shortcuts", + "version": "2.39.2-SNAPSHOT", + "license": "MIT", + "private": true, + "main": "build/index.js", + "module": "build/index.mjs", + "types": "build/index.d.ts", + "files": [ + "build" + ], + "scripts": { + "build": "tsup ./src/index.ts -d build --format esm,cjs --dts", + "lint": "eslint src", + "typecheck": "tsc" + }, + "peerDependencies": { + "react": "17" + }, + "dependencies": { + "mousetrap": "1.6.5" + }, + "devDependencies": { + "@types/mousetrap": "1.6.5", + "@scm-manager/babel-preset": "^2.13.1", + "@scm-manager/prettier-config": "^2.10.1", + "@scm-manager/eslint-config": "^2.16.0", + "@scm-manager/tsconfig": "^2.13.0" + }, + "babel": { + "presets": [ + "@scm-manager/babel-preset" + ] + }, + "prettier": "@scm-manager/prettier-config", + "eslintConfig": { + "extends": "@scm-manager/eslint-config" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/scm-ui/ui-shortcuts/src/index.ts b/scm-ui/ui-shortcuts/src/index.ts new file mode 100644 index 0000000000..fb168ce6cd --- /dev/null +++ b/scm-ui/ui-shortcuts/src/index.ts @@ -0,0 +1,27 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +export { default as useShortcut } from "./useShortcut"; +export { default as useShortcutDocs, ShortcutDocsContextProvider } from "./useShortcutDocs"; +export { default as usePauseShortcuts } from "./usePauseShortcuts"; diff --git a/scm-ui/ui-webapp/src/shortcuts/usePauseShortcuts.ts b/scm-ui/ui-shortcuts/src/usePauseShortcuts.ts similarity index 96% rename from scm-ui/ui-webapp/src/shortcuts/usePauseShortcuts.ts rename to scm-ui/ui-shortcuts/src/usePauseShortcuts.ts index 451613d2a3..e7fcc09a08 100644 --- a/scm-ui/ui-webapp/src/shortcuts/usePauseShortcuts.ts +++ b/scm-ui/ui-shortcuts/src/usePauseShortcuts.ts @@ -24,6 +24,7 @@ import { useEffect } from "react"; import Mousetrap from "mousetrap"; +import "mousetrap/plugins/pause/mousetrap-pause.min.js"; /** * Pauses or unpauses all shortcuts provided by {@link useShortcut}. diff --git a/scm-ui/ui-webapp/src/shortcuts/useShortcut.ts b/scm-ui/ui-shortcuts/src/useShortcut.ts similarity index 77% rename from scm-ui/ui-webapp/src/shortcuts/useShortcut.ts rename to scm-ui/ui-shortcuts/src/useShortcut.ts index 2e0238ea32..690a800b0b 100644 --- a/scm-ui/ui-webapp/src/shortcuts/useShortcut.ts +++ b/scm-ui/ui-shortcuts/src/useShortcut.ts @@ -33,6 +33,13 @@ export type UseShortcutOptions = { * @default true */ active?: boolean; + + /** + * The translated description used for the shortcut documentation. + * + * If no description is supplied, there will be no entry in the shortcut summary table. + */ + description?: string; }; /** @@ -62,8 +69,7 @@ export type UseShortcutOptions = { * Please also refer to the examples. * * @param key The keycode combination that triggers the callback - * @param callback The function that is executed when the key combination is pressed - * @param description The translated description used for the shortcut documentation + * @param callback The function that is executed when the key combination is pressed, returning `true` additionally executes default browser behaviour * @param options Whether the shortcut is currently active, defaults to true * @example useShortcut("a b", ...) * @example useShortcut("ctrl+shift+k", ...) @@ -72,29 +78,33 @@ export type UseShortcutOptions = { */ export default function useShortcut( key: string, - callback: (e: KeyboardEvent) => void, - description: string, + callback: (e: KeyboardEvent) => void | boolean, options?: UseShortcutOptions ) { const { add, remove } = useShortcutDocs(); useEffect(() => { - const active = !options || options.active === undefined || options.active; + const active = options?.active ?? true; + const description = options?.description; if (active) { - add(key, description); + if (description) { + add(key, description); + } Mousetrap.bind(key, (e) => { - callback(e); + const callbackResult = callback(e); /* - * Returning false disables default event behaviour and stops event bubbling. + * Returning false by default disables standard browser event behaviour and stops event bubbling. * Otherwise, a shortcut that moves focus to an input field would cause the key to be entered into the input at the same time. - * We could move the decision to the callback, but this behaviour is an implementation detail of Mousetrap which we would like to hide. + * Shortcuts can explicitly return `true` to re-enable event bubbling and browser behaviour. */ - return false; + return callbackResult ?? false; }); } return () => { - remove(key); + if (description) { + remove(key); + } Mousetrap.unbind(key); }; - }, [key, callback, add, remove, options, description]); + }, [key, callback, add, remove, options]); } diff --git a/scm-ui/ui-webapp/src/shortcuts/useShortcutDocs.tsx b/scm-ui/ui-shortcuts/src/useShortcutDocs.tsx similarity index 95% rename from scm-ui/ui-webapp/src/shortcuts/useShortcutDocs.tsx rename to scm-ui/ui-shortcuts/src/useShortcutDocs.tsx index 4ae9cbe6fa..cc992be046 100644 --- a/scm-ui/ui-webapp/src/shortcuts/useShortcutDocs.tsx +++ b/scm-ui/ui-shortcuts/src/useShortcutDocs.tsx @@ -22,7 +22,8 @@ * SOFTWARE. */ -import React, { FC, useContext, useMemo, useRef } from "react"; +import type { FC } from "react"; +import React, { useContext, useMemo, useRef } from "react"; export type ShortcutDocsContextType = { docs: Readonly>; diff --git a/scm-ui/ui-shortcuts/tsconfig.json b/scm-ui/ui-shortcuts/tsconfig.json new file mode 100644 index 0000000000..bd1e5ff43c --- /dev/null +++ b/scm-ui/ui-shortcuts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@scm-manager/tsconfig", + "include": [ + "./src" + ] +} diff --git a/scm-ui/ui-webapp/package.json b/scm-ui/ui-webapp/package.json index 75aa740032..3d58557579 100644 --- a/scm-ui/ui-webapp/package.json +++ b/scm-ui/ui-webapp/package.json @@ -10,6 +10,7 @@ "@scm-manager/ui-modules": "2.39.2-SNAPSHOT", "@scm-manager/ui-syntaxhighlighting": "2.39.2-SNAPSHOT", "@scm-manager/ui-text": "2.39.2-SNAPSHOT", + "@scm-manager/ui-shortcuts": "2.39.2-SNAPSHOT", "@scm-manager/ui-legacy": "2.39.2-SNAPSHOT", "classnames": "^2.2.5", "history": "^4.10.1", @@ -27,7 +28,6 @@ "string_score": "^0.1.22", "styled-components": "^5.3.5", "systemjs": "0.21.6", - "mousetrap": "^1.6.5", "ua-parser-js": "^1.0.2" }, "scripts": { @@ -50,7 +50,6 @@ "@types/react-router-dom": "^5.3.3", "@types/styled-components": "^5.1.25", "@types/systemjs": "^0.20.6", - "@types/mousetrap": "^1.6.9", "@types/ua-parser-js": "^0.7.36", "fetch-mock": "^7.5.1", "react-test-renderer": "^17.0.1" diff --git a/scm-ui/ui-webapp/public/locales/de/repos.json b/scm-ui/ui-webapp/public/locales/de/repos.json index 744da2f5da..80a9a5a691 100644 --- a/scm-ui/ui-webapp/public/locales/de/repos.json +++ b/scm-ui/ui-webapp/public/locales/de/repos.json @@ -540,10 +540,10 @@ } }, "shortcuts": { - "info": "Info", - "branches": "Branches", - "tags": "Tags", - "code": "Code", - "settings": "Einstellungen" + "info": "Wechsel zur Repository-Info", + "branches": "Wechsel zu den Branches", + "tags": "Wechsel zu den Tags", + "code": "Wechsel zum Code", + "settings": "Wechsel zu den Einstellungen" } } diff --git a/scm-ui/ui-webapp/public/locales/en/repos.json b/scm-ui/ui-webapp/public/locales/en/repos.json index 9acd935234..7e005254ea 100644 --- a/scm-ui/ui-webapp/public/locales/en/repos.json +++ b/scm-ui/ui-webapp/public/locales/en/repos.json @@ -547,10 +547,10 @@ } }, "shortcuts": { - "info": "Info", - "branches": "Branches", - "tags": "Tags", - "code": "Code", - "settings": "Settings" + "info": "Switch to repository info", + "branches": "Switch to branches", + "tags": "Switch to tags", + "code": "Switch to code", + "settings": "Switch to settings" } } diff --git a/scm-ui/ui-webapp/src/containers/App.tsx b/scm-ui/ui-webapp/src/containers/App.tsx index 73140f9aef..e4b5beb40a 100644 --- a/scm-ui/ui-webapp/src/containers/App.tsx +++ b/scm-ui/ui-webapp/src/containers/App.tsx @@ -30,7 +30,7 @@ import { useIndex, useSubject } from "@scm-manager/ui-api"; import { ErrorPage, Footer, Header, Loading } from "@scm-manager/ui-components"; import { binder } from "@scm-manager/ui-extensions"; import usePauseShortcutsWhenModalsActive from "../shortcuts/usePauseShortcutsWhenModalsActive"; -import useShortcut from "../shortcuts/useShortcut"; +import { useShortcut } from "@scm-manager/ui-shortcuts"; import Login from "./Login"; import NavigationBar from "./NavigationBar"; import styled from "styled-components"; @@ -41,6 +41,7 @@ const AppWrapper = styled.div` display: flex; flex-direction: column; `; + const App: FC = () => { const { data: index } = useIndex(); const { isLoading, error, isAuthenticated, isAnonymous, me } = useSubject(); @@ -49,17 +50,21 @@ const App: FC = () => { const history = useHistory(); - useShortcut("option+r", () => history.push("/repos/"), t("shortcuts.repositories"), { + useShortcut("option+r", () => history.push("/repos/"), { active: !!index?._links["repositories"], + description: t("shortcuts.repositories"), }); - useShortcut("option+u", () => history.push("/users/"), t("shortcuts.users"), { + useShortcut("option+u", () => history.push("/users/"), { active: !!index?._links["users"], + description: t("shortcuts.users"), }); - useShortcut("option+g", () => history.push("/groups/"), t("shortcuts.groups"), { + useShortcut("option+g", () => history.push("/groups/"), { active: !!index?._links["groups"], + description: t("shortcuts.groups"), }); - useShortcut("option+a", () => history.push("/admin/"), t("shortcuts.admin"), { + useShortcut("option+a", () => history.push("/admin/"), { active: !!index?._links["config"], + description: t("shortcuts.admin"), }); if (!index) { @@ -85,7 +90,7 @@ const App: FC = () => { } return ( - +
diff --git a/scm-ui/ui-webapp/src/containers/Index.tsx b/scm-ui/ui-webapp/src/containers/Index.tsx index edba6e458d..d02b1ab749 100644 --- a/scm-ui/ui-webapp/src/containers/Index.tsx +++ b/scm-ui/ui-webapp/src/containers/Index.tsx @@ -23,7 +23,7 @@ */ import React, { FC, useState } from "react"; import App from "./App"; -import { ActiveModalCountContextProvider, ErrorBoundary, Header, Loading } from "@scm-manager/ui-components"; +import { ErrorBoundary, Header, Loading } from "@scm-manager/ui-components"; import PluginLoader from "./PluginLoader"; import ScrollToTop from "./ScrollToTop"; import IndexErrorPage from "./IndexErrorPage"; @@ -33,7 +33,6 @@ import i18next from "i18next"; import { binder, extensionPoints } from "@scm-manager/ui-extensions"; import InitializationAdminAccountStep from "./InitializationAdminAccountStep"; import InitializationPluginWizardStep from "./InitializationPluginWizardStep"; -import { ShortcutDocsContextProvider } from "../shortcuts/useShortcutDocs"; const Index: FC = () => { const { isLoading, error, data } = useIndex(); @@ -61,15 +60,11 @@ const Index: FC = () => { return ( - - - - setPluginsLoaded(true)}> - - - - - + + setPluginsLoaded(true)}> + + + ); diff --git a/scm-ui/ui-webapp/src/containers/OmniSearch.tsx b/scm-ui/ui-webapp/src/containers/OmniSearch.tsx index 5c0e8a3649..a10f1acc62 100644 --- a/scm-ui/ui-webapp/src/containers/OmniSearch.tsx +++ b/scm-ui/ui-webapp/src/containers/OmniSearch.tsx @@ -46,7 +46,7 @@ import SyntaxModal from "../search/SyntaxModal"; import SearchErrorNotification from "../search/SearchErrorNotification"; import queryString from "query-string"; import { orderTypes } from "../search/Search"; -import useShortcut from "../shortcuts/useShortcut"; +import { useShortcut } from "@scm-manager/ui-shortcuts"; const Input = styled.input` border-radius: 4px !important; @@ -358,7 +358,9 @@ const OmniSearch: FC = () => { searchTypes.sort(orderTypes(t)); const id = useCallback(namespaceAndName, []); - useShortcut("/", () => searchInputRef.current?.focus(), t("shortcuts.search")); + useShortcut("/", () => searchInputRef.current?.focus(), { + description: t("shortcuts.search"), + }); const entries = useMemo(() => { const newEntries = []; diff --git a/scm-ui/ui-webapp/src/index.tsx b/scm-ui/ui-webapp/src/index.tsx index c4517ad717..0c38d696b7 100644 --- a/scm-ui/ui-webapp/src/index.tsx +++ b/scm-ui/ui-webapp/src/index.tsx @@ -30,16 +30,13 @@ import i18n from "./i18n"; import { BrowserRouter as Router } from "react-router-dom"; -import { urls } from "@scm-manager/ui-components"; +import { ActiveModalCountContextProvider, urls } from "@scm-manager/ui-components"; import { binder, extensionPoints } from "@scm-manager/ui-extensions"; import ChangesetShortLink from "./repos/components/changesets/ChangesetShortLink"; import "./tokenExpired"; import { ApiProvider } from "@scm-manager/ui-api"; -// Used by useShortcut -import "mousetrap"; -// Used by usePauseShortcuts -import "mousetrap/plugins/pause/mousetrap-pause.min"; +import { ShortcutDocsContextProvider } from "@scm-manager/ui-shortcuts"; binder.bind("changeset.description.tokens", ChangesetShortLink); @@ -51,9 +48,13 @@ if (!root) { ReactDOM.render( - - - + + + + + + + , root diff --git a/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx b/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx index d79ce7e41c..883a3ae45e 100644 --- a/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx @@ -62,7 +62,7 @@ import CompareRoot from "../compare/CompareRoot"; import TagRoot from "../tags/container/TagRoot"; import { useIndexLinks, useNamespaceAndNameContext, useRepository } from "@scm-manager/ui-api"; import styled from "styled-components"; -import useShortcut from "../../shortcuts/useShortcut"; +import { useShortcut } from "@scm-manager/ui-shortcuts"; const TagGroup = styled.span` & > * { @@ -111,17 +111,24 @@ const RepositoryRoot = () => { return ""; }, [repository]); - useShortcut("g i", () => history.push(`${url}/info`), t("shortcuts.info")); - useShortcut("g b", () => history.push(`${url}/branches/`), t("shortcuts.branches"), { + useShortcut("g i", () => history.push(`${url}/info`), { + description: t("shortcuts.info"), + }); + useShortcut("g b", () => history.push(`${url}/branches/`), { active: !!repository?._links["branches"], + description: t("shortcuts.branches"), }); - useShortcut("g t", () => history.push(`${url}/tags/`), t("shortcuts.tags"), { + useShortcut("g t", () => history.push(`${url}/tags/`), { active: !!repository?._links["tags"], + description: t("shortcuts.tags"), }); - useShortcut("g c", () => history.push(evaluateDestinationForCodeLink()), t("shortcuts.code"), { + useShortcut("g c", () => history.push(evaluateDestinationForCodeLink()), { active: !!repository?._links[codeLinkname], + description: t("shortcuts.code"), + }); + useShortcut("g s", () => history.push(`${url}/settings/general`), { + description: t("shortcuts.settings"), }); - useShortcut("g s", () => history.push(`${url}/settings/general`), t("shortcuts.settings")); useEffect(() => { if (repository) { diff --git a/scm-ui/ui-webapp/src/shortcuts/ShortcutDocsModal.tsx b/scm-ui/ui-webapp/src/shortcuts/ShortcutDocsModal.tsx index 6403823395..cef2f8ab64 100644 --- a/scm-ui/ui-webapp/src/shortcuts/ShortcutDocsModal.tsx +++ b/scm-ui/ui-webapp/src/shortcuts/ShortcutDocsModal.tsx @@ -22,9 +22,8 @@ * SOFTWARE. */ import React, { useState } from "react"; -import useShortcutDocs from "./useShortcutDocs"; +import { useShortcutDocs, useShortcut } from "@scm-manager/ui-shortcuts"; import { Column, Modal, Table } from "@scm-manager/ui-components"; -import useShortcut from "./useShortcut"; import { useTranslation } from "react-i18next"; import classNames from "classnames"; import splitKeyCombination from "./splitKeyCombination"; diff --git a/scm-ui/ui-webapp/src/shortcuts/usePauseShortcutsWhenModalsActive.ts b/scm-ui/ui-webapp/src/shortcuts/usePauseShortcutsWhenModalsActive.ts index 46b91dc111..315d6e813c 100644 --- a/scm-ui/ui-webapp/src/shortcuts/usePauseShortcutsWhenModalsActive.ts +++ b/scm-ui/ui-webapp/src/shortcuts/usePauseShortcutsWhenModalsActive.ts @@ -23,7 +23,7 @@ */ import { useActiveModals } from "@scm-manager/ui-components"; -import usePauseShortcuts from "./usePauseShortcuts"; +import { usePauseShortcuts } from "@scm-manager/ui-shortcuts"; /** * Keyboard shortcuts are not active in modals using {@link useActiveModals} to determine whether any modals are open. diff --git a/yarn.lock b/yarn.lock index 61435887e3..b33ef59686 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3889,10 +3889,10 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== -"@types/mousetrap@^1.6.9": - version "1.6.9" - resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.9.tgz#f1ef9adbd1eac3466f21b6988b1c82c633a45340" - integrity sha512-HUAiN65VsRXyFCTicolwb5+I7FM6f72zjMWr+ajGk+YTvzBgXqa2A5U7d+rtsouAkunJ5U4Sb5lNJjo9w+nmXg== +"@types/mousetrap@1.6.5": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.5.tgz#e95569aa6273dbe0ed1814f86287547cc06e93c9" + integrity sha512-OwVhKFim9Y/MprzCe4I6a59p31pMy8+LrtP6qS7J0kaOxYmW6VVJPBw5NYm+g7nSbgPUz22FvqU1F1hC5YGTfg== "@types/node-fetch@^2.5.7": version "2.6.2" @@ -13520,7 +13520,7 @@ moo@^0.5.0: resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w== -mousetrap@^1.6.5: +mousetrap@1.6.5: version "1.6.5" resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9" integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==