diff --git a/packages/editor/src/index.tsx b/packages/editor/src/index.tsx index 7d4edc74..997a7bad 100644 --- a/packages/editor/src/index.tsx +++ b/packages/editor/src/index.tsx @@ -9,7 +9,8 @@ import { PersistenceManager, RESTPersistenceManager, DesignerOptionsBuilder, - Designer + Designer, + DesignerKeyboard, } from '@wisemapping/mindplot'; import FR from './compiled-lang/fr.json'; import ES from './compiled-lang/es.json'; @@ -43,6 +44,7 @@ export type EditorPropsType = { readOnlyMode: boolean; locale?: string; onAction: (action: ToolbarActionType) => void; + hotkeys?: boolean; }; const loadLocaleData = (locale: string) => { @@ -117,11 +119,20 @@ const Editor = ({ isTryMode: isTryMode, locale = 'en', onAction, + hotkeys = true, }: EditorPropsType): React.ReactElement => { React.useEffect(() => { initCallback(locale); }, []); + React.useEffect(() => { + if (hotkeys) { + DesignerKeyboard.resume(); + } else { + DesignerKeyboard.pause(); + } + }, [hotkeys]); + return ( void; class DesignerKeyboard extends Keyboard { // eslint-disable-next-line no-use-before-define static _instance: DesignerKeyboard; + static _disabled: boolean; + constructor(designer: Designer) { super(); $assert(designer, 'designer can not be null'); this._registerEvents(designer); } + addShortcut(shortcuts: string[] | string, callback: EventCallback): void { + super.addShortcut(shortcuts, (e: Event) => { + if (DesignerKeyboard.isDisabled()) { + return; + } + callback(e); + }); + } + private _registerEvents(designer: Designer) { // Try with the keyboard .. const model = designer.getModel(); @@ -246,6 +258,10 @@ class DesignerKeyboard extends Keyboard { $(document).on('keypress', (event) => { let keyCode: number; + + if (DesignerKeyboard.isDisabled()) { + return; + } // Firefox doesn't skip special keys for keypress event... if (event.key && excludes.includes(event.key.toLowerCase())) { return; @@ -373,6 +389,19 @@ class DesignerKeyboard extends Keyboard { static register = function register(designer: Designer) { this._instance = new DesignerKeyboard(designer); + this._disabled = false; + }; + + static pause = function pause() { + this._disabled = true; + }; + + static resume = function resume() { + this._disabled = false; + }; + + static isDisabled = function isDisabled() { + return this._disabled; }; static specialKeys = { diff --git a/packages/mindplot/src/components/Keyboard.ts b/packages/mindplot/src/components/Keyboard.ts index 5355c752..d357a584 100644 --- a/packages/mindplot/src/components/Keyboard.ts +++ b/packages/mindplot/src/components/Keyboard.ts @@ -18,7 +18,7 @@ import $ from 'jquery'; class Keyboard { - addShortcut(shortcuts, callback) { + addShortcut(shortcuts: string[] | string, callback) { const shortcutsArray = Array.isArray(shortcuts) ? shortcuts : [shortcuts]; shortcutsArray.forEach((shortcut) => { $(document).bind('keydown', shortcut, callback); diff --git a/packages/mindplot/src/index.ts b/packages/mindplot/src/index.ts index 9a3569b5..ed95a2ee 100644 --- a/packages/mindplot/src/index.ts +++ b/packages/mindplot/src/index.ts @@ -27,6 +27,7 @@ import DesignerOptionsBuilder from './components/DesignerOptionsBuilder'; import ImageExporterFactory from './components/export/ImageExporterFactory'; import TextExporterFactory from './components/export/TextExporterFactory'; import Exporter from './components/export/Exporter'; +import DesignerKeyboard from './components/DesignerKeyboard'; import { buildDesigner, @@ -54,4 +55,5 @@ export { ImageExporterFactory, Exporter, $notify, + DesignerKeyboard, }; diff --git a/packages/webapp/src/components/editor-page/index.tsx b/packages/webapp/src/components/editor-page/index.tsx index 055ccb49..3372a915 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -3,6 +3,8 @@ import ActionDispatcher from '../maps-page/action-dispatcher'; import { ActionType } from '../maps-page/action-chooser'; import Editor from '@wisemapping/editor'; import AppI18n from '../../classes/app-i18n'; +import { useSelector } from 'react-redux'; +import { hotkeysEnabled } from '../../redux/editorSlice'; export type EditorPropsType = { mapId: number; @@ -11,12 +13,12 @@ export type EditorPropsType = { const EditorPage = ({ mapId, ...props }: EditorPropsType): React.ReactElement => { const [activeDialog, setActiveDialog] = React.useState(null); - + const hotkeys = useSelector(hotkeysEnabled); // Load user locale ... const userLocale = AppI18n.getUserLocale(); return <> - + { activeDialog && void; @@ -23,6 +25,13 @@ export type DialogProps = { }; const BaseDialog = (props: DialogProps): React.ReactElement => { + const dispatch = useDispatch(); + useEffect(() => { + dispatch(disableHotkeys()); + return () => { + dispatch(enableHotkeys()) + }; + }, []); const { onClose, onSubmit, maxWidth = 'sm', PaperProps } = props; const handleOnSubmit = (e: React.FormEvent) => { diff --git a/packages/webapp/src/redux/clientSlice.ts b/packages/webapp/src/redux/clientSlice.ts index 5c51e060..ef7329df 100644 --- a/packages/webapp/src/redux/clientSlice.ts +++ b/packages/webapp/src/redux/clientSlice.ts @@ -4,6 +4,7 @@ import { useQuery } from 'react-query'; import Client, { AccountInfo, ErrorInfo, MapInfo } from '../classes/client'; import { useSelector } from 'react-redux'; import AppConfig from '../classes/app-config'; +import { RootState } from './rootReducer'; export interface ClientStatus { @@ -59,13 +60,11 @@ export const fetchAccount = (): AccountInfo | undefined => { return data; }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const activeInstance = (state: any): Client => { +export const activeInstance = (state: RootState): Client => { return state.client.instance; }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const activeInstanceStatus = (state: any): ClientStatus => { +export const activeInstanceStatus = (state: RootState): ClientStatus => { return state.client.status; }; diff --git a/packages/webapp/src/redux/editorSlice.ts b/packages/webapp/src/redux/editorSlice.ts new file mode 100644 index 00000000..a2b055b3 --- /dev/null +++ b/packages/webapp/src/redux/editorSlice.ts @@ -0,0 +1,30 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { RootState } from "./rootReducer"; + +export interface EditorState { + hotkeysEnabled: boolean; +} + +const initialState: EditorState = { + hotkeysEnabled: true, +}; + +export const editorSlice = createSlice({ + name: 'editor', + initialState: initialState, + reducers: { + disableHotkeys(state) { + state.hotkeysEnabled = false; + }, + enableHotkeys(state) { + state.hotkeysEnabled = true; + }, + }, +}); + +export const hotkeysEnabled = (state: RootState): boolean => { + return state.editor.hotkeysEnabled; +}; + +export const { disableHotkeys, enableHotkeys } = editorSlice.actions; +export default editorSlice.reducer; \ No newline at end of file diff --git a/packages/webapp/src/redux/rootReducer.ts b/packages/webapp/src/redux/rootReducer.ts new file mode 100644 index 00000000..cd737710 --- /dev/null +++ b/packages/webapp/src/redux/rootReducer.ts @@ -0,0 +1,12 @@ +import { combineReducers } from '@reduxjs/toolkit'; +import clientReducer from './clientSlice'; +import editorReducer from './editorSlice'; + +const rootReducer = combineReducers({ + client: clientReducer, + editor: editorReducer, +}); + +export type RootState = ReturnType; + +export default rootReducer; \ No newline at end of file diff --git a/packages/webapp/src/redux/store.ts b/packages/webapp/src/redux/store.ts index 8400fa48..70ee69d1 100644 --- a/packages/webapp/src/redux/store.ts +++ b/packages/webapp/src/redux/store.ts @@ -1,11 +1,9 @@ import { configureStore } from '@reduxjs/toolkit'; -import clientReducer from './clientSlice'; +import rootReducer from './rootReducer'; // Create Service object... const store = configureStore({ - reducer: { - client: clientReducer, - }, + reducer: rootReducer, }); export default store;