Uniformize folder structure (#693)

* Uniformize folder structure

* Fix icons

* Fix icons

* Fix tests

* Fix tests
This commit is contained in:
Charles Bochet
2023-07-16 14:29:28 -07:00
committed by GitHub
parent 900ec5572f
commit 6ced8434bd
462 changed files with 931 additions and 960 deletions

View File

@ -0,0 +1,30 @@
import { useEffect } from 'react';
import { useRecoilValue } from 'recoil';
import { currentHotkeyScopeState } from '@/ui/hotkey/states/internal/currentHotkeyScopeState';
import { AppHotkeyScope } from '../../types/AppHotkeyScope';
import { useHotkeyScopes } from './useHotkeyScopes';
export function useHotkeyScopeAutoSync() {
const { setHotkeyScopes } = useHotkeyScopes();
const currentHotkeyScope = useRecoilValue(currentHotkeyScopeState);
useEffect(() => {
const scopesToSet: string[] = [];
if (currentHotkeyScope.customScopes?.commandMenu) {
scopesToSet.push(AppHotkeyScope.CommandMenu);
}
if (currentHotkeyScope?.customScopes?.goto) {
scopesToSet.push(AppHotkeyScope.Goto);
}
scopesToSet.push(currentHotkeyScope.scope);
setHotkeyScopes(scopesToSet);
}, [setHotkeyScopes, currentHotkeyScope]);
}

View File

@ -0,0 +1,103 @@
import { useHotkeysContext } from 'react-hotkeys-hook';
import { useRecoilCallback } from 'recoil';
import { internalHotkeysEnabledScopesState } from '../../states/internal/internalHotkeysEnabledScopesState';
export function useHotkeyScopes() {
const { disableScope, enableScope } = useHotkeysContext();
const disableAllHotkeyScopes = useRecoilCallback(
({ set, snapshot }) => {
return async () => {
const enabledScopes = await snapshot.getPromise(
internalHotkeysEnabledScopesState,
);
for (const enabledScope of enabledScopes) {
disableScope(enabledScope);
}
set(internalHotkeysEnabledScopesState, []);
};
},
[disableScope],
);
const enableHotkeyScope = useRecoilCallback(
({ set, snapshot }) => {
return async (scopeToEnable: string) => {
const enabledScopes = await snapshot.getPromise(
internalHotkeysEnabledScopesState,
);
if (!enabledScopes.includes(scopeToEnable)) {
enableScope(scopeToEnable);
set(internalHotkeysEnabledScopesState, [
...enabledScopes,
scopeToEnable,
]);
}
};
},
[enableScope],
);
const disableHotkeyScope = useRecoilCallback(
({ set, snapshot }) => {
return async (scopeToDisable: string) => {
const enabledScopes = await snapshot.getPromise(
internalHotkeysEnabledScopesState,
);
const scopeToRemoveIndex = enabledScopes.findIndex(
(scope) => scope === scopeToDisable,
);
if (scopeToRemoveIndex > -1) {
disableScope(scopeToDisable);
enabledScopes.splice(scopeToRemoveIndex);
set(internalHotkeysEnabledScopesState, enabledScopes);
}
};
},
[disableScope],
);
const setHotkeyScopes = useRecoilCallback(
({ set, snapshot }) => {
return async (scopesToSet: string[]) => {
const enabledScopes = await snapshot.getPromise(
internalHotkeysEnabledScopesState,
);
const scopesToDisable = enabledScopes.filter(
(enabledScope) => !scopesToSet.includes(enabledScope),
);
const scopesToEnable = scopesToSet.filter(
(scopeToSet) => !enabledScopes.includes(scopeToSet),
);
for (const scopeToDisable of scopesToDisable) {
disableScope(scopeToDisable);
}
for (const scopeToEnable of scopesToEnable) {
enableScope(scopeToEnable);
}
set(internalHotkeysEnabledScopesState, scopesToSet);
};
},
[disableScope, enableScope],
);
return {
disableAllHotkeyScopes,
enableHotkeyScope,
disableHotkeyScope,
setHotkeyScopes,
};
}

View File

@ -0,0 +1,25 @@
import { Keys } from 'react-hotkeys-hook/dist/types';
import { useNavigate } from 'react-router-dom';
import { AppHotkeyScope } from '../types/AppHotkeyScope';
import { useSequenceHotkeys } from './useSequenceScopedHotkeys';
export function useGoToHotkeys(key: Keys, location: string) {
const navigate = useNavigate();
useSequenceHotkeys(
'g',
key,
() => {
navigate(location);
},
AppHotkeyScope.Goto,
{
enableOnContentEditable: true,
enableOnFormTags: true,
preventDefault: true,
},
[navigate],
);
}

View File

@ -0,0 +1,39 @@
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { currentHotkeyScopeState } from '../states/internal/currentHotkeyScopeState';
import { CustomHotkeyScopes } from '../types/CustomHotkeyScope';
import { HotkeyScope } from '../types/HotkeyScope';
import { useSetHotkeyScope } from './useSetHotkeyScope';
export function usePreviousHotkeyScope() {
const [previousHotkeyScope, setPreviousHotkeyScope] =
useState<HotkeyScope | null>();
const setHotkeyScope = useSetHotkeyScope();
const currentHotkeyScope = useRecoilValue(currentHotkeyScopeState);
function goBackToPreviousHotkeyScope() {
if (previousHotkeyScope) {
setHotkeyScope(
previousHotkeyScope.scope,
previousHotkeyScope.customScopes,
);
}
}
function setHotkeyScopeAndMemorizePreviousScope(
scope: string,
customScopes?: CustomHotkeyScopes,
) {
setPreviousHotkeyScope(currentHotkeyScope);
setHotkeyScope(scope, customScopes);
}
return {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
};
}

View File

@ -0,0 +1,43 @@
import { useHotkeys } from 'react-hotkeys-hook';
import {
Hotkey,
HotkeyCallback,
Keys,
Options,
OptionsOrDependencyArray,
} from 'react-hotkeys-hook/dist/types';
import { useRecoilState } from 'recoil';
import { pendingHotkeyState } from '../states/internal/pendingHotkeysState';
export function useScopedHotkeys(
keys: Keys,
callback: HotkeyCallback,
scope: string,
dependencies?: OptionsOrDependencyArray,
options: Options = {
enableOnContentEditable: true,
enableOnFormTags: true,
preventDefault: true,
},
) {
const [pendingHotkey, setPendingHotkey] = useRecoilState(pendingHotkeyState);
function callbackIfDirectKey(
keyboardEvent: KeyboardEvent,
hotkeysEvent: Hotkey,
) {
if (!pendingHotkey) {
callback(keyboardEvent, hotkeysEvent);
return;
}
setPendingHotkey(null);
}
return useHotkeys(
keys,
callbackIfDirectKey,
{ ...options, scopes: [scope] },
dependencies,
);
}

View File

@ -0,0 +1,42 @@
import { Options, useHotkeys } from 'react-hotkeys-hook';
import { Keys } from 'react-hotkeys-hook/dist/types';
import { useRecoilState } from 'recoil';
import { pendingHotkeyState } from '../states/internal/pendingHotkeysState';
export function useSequenceHotkeys(
firstKey: Keys,
secondKey: Keys,
callback: () => void,
scope: string,
options: Options = {
enableOnContentEditable: true,
enableOnFormTags: true,
preventDefault: true,
},
deps: any[] = [],
) {
const [pendingHotkey, setPendingHotkey] = useRecoilState(pendingHotkeyState);
useHotkeys(
firstKey,
() => {
setPendingHotkey(firstKey);
},
{ ...options, scopes: [scope] },
[setPendingHotkey],
);
useHotkeys(
secondKey,
() => {
if (pendingHotkey !== firstKey) {
return;
}
setPendingHotkey(null);
callback();
},
{ ...options, scopes: [scope] },
[pendingHotkey, setPendingHotkey, ...deps],
);
}

View File

@ -0,0 +1,59 @@
import { useRecoilCallback } from 'recoil';
import { isDefined } from '~/utils/isDefined';
import { DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES } from '../constants';
import { currentHotkeyScopeState } from '../states/internal/currentHotkeyScopeState';
import { CustomHotkeyScopes } from '../types/CustomHotkeyScope';
function isCustomScopesEqual(
customScopesA: CustomHotkeyScopes | undefined,
customScopesB: CustomHotkeyScopes | undefined,
) {
return (
customScopesA?.commandMenu === customScopesB?.commandMenu &&
customScopesA?.goto === customScopesB?.goto
);
}
export function useSetHotkeyScope() {
return useRecoilCallback(
({ snapshot, set }) =>
async (HotkeyScopeToSet: string, customScopes?: CustomHotkeyScopes) => {
const currentHotkeyScope = await snapshot.getPromise(
currentHotkeyScopeState,
);
if (currentHotkeyScope.scope === HotkeyScopeToSet) {
if (!isDefined(customScopes)) {
if (
isCustomScopesEqual(
currentHotkeyScope?.customScopes,
DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES,
)
) {
return;
}
} else {
if (
isCustomScopesEqual(
currentHotkeyScope?.customScopes,
customScopes,
)
) {
return;
}
}
}
set(currentHotkeyScopeState, {
scope: HotkeyScopeToSet,
customScopes: {
commandMenu: customScopes?.commandMenu ?? true,
goto: customScopes?.goto ?? false,
},
});
},
[],
);
}