Feat/better hotkeys scope (#526)
* Working version * fix * Fixed console log * Fix lint * wip * Fix * Fix * consolelog --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
21
front/src/modules/ui/tables/hooks/useClearCellInEditMode.ts
Normal file
21
front/src/modules/ui/tables/hooks/useClearCellInEditMode.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { currentCellInEditModePositionState } from '../states/currentCellInEditModePositionState';
|
||||
import { isCellInEditModeFamilyState } from '../states/isCellInEditModeFamilyState';
|
||||
import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState';
|
||||
|
||||
export function useCloseCurrentCellInEditMode() {
|
||||
return useRecoilCallback(({ set, snapshot }) => {
|
||||
return async () => {
|
||||
const currentCellInEditModePosition = await snapshot.getPromise(
|
||||
currentCellInEditModePositionState,
|
||||
);
|
||||
|
||||
set(isCellInEditModeFamilyState(currentCellInEditModePosition), false);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||
|
||||
set(isSomeInputInEditModeState, false);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
19
front/src/modules/ui/tables/hooks/useDisableSoftFocus.ts
Normal file
19
front/src/modules/ui/tables/hooks/useDisableSoftFocus.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isSoftFocusActiveState } from '../states/isSoftFocusActiveState';
|
||||
import { isSoftFocusOnCellFamilyState } from '../states/isSoftFocusOnCellFamilyState';
|
||||
import { softFocusPositionState } from '../states/softFocusPositionState';
|
||||
|
||||
export function useDisableSoftFocus() {
|
||||
return useRecoilCallback(({ set, snapshot }) => {
|
||||
return () => {
|
||||
const currentPosition = snapshot
|
||||
.getLoadable(softFocusPositionState)
|
||||
.valueOrThrow();
|
||||
|
||||
set(isSoftFocusActiveState, false);
|
||||
|
||||
set(isSoftFocusOnCellFamilyState(currentPosition), false);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
@ -1,11 +1,9 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { TABLE_MIN_COLUMN_NUMBER_BECAUSE_OF_CHECKBOX_COLUMN } from '../constants';
|
||||
import { entityTableDimensionsState } from '../states/entityTableDimensionsState';
|
||||
|
||||
import { useResetTableRowSelection } from './useResetTableRowSelection';
|
||||
import { useSetSoftFocusPosition } from './useSetSoftFocusPosition';
|
||||
|
||||
export type TableDimensions = {
|
||||
numberOfRows: number;
|
||||
@ -30,13 +28,4 @@ export function useInitializeEntityTable({
|
||||
numberOfRows,
|
||||
});
|
||||
}, [numberOfRows, numberOfColumns, setTableDimensions]);
|
||||
|
||||
const setSoftFocusPosition = useSetSoftFocusPosition();
|
||||
|
||||
useEffect(() => {
|
||||
setSoftFocusPosition({
|
||||
row: 0,
|
||||
column: TABLE_MIN_COLUMN_NUMBER_BECAUSE_OF_CHECKBOX_COLUMN,
|
||||
});
|
||||
}, [setSoftFocusPosition]);
|
||||
}
|
||||
|
||||
24
front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts
Normal file
24
front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { useCurrentHotkeysScope } from '@/hotkeys/hooks/useCurrentHotkeysScope';
|
||||
import { useResetHotkeysScopeStack } from '@/hotkeys/hooks/useResetHotkeysScopeStack';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { useCloseCurrentCellInEditMode } from './useClearCellInEditMode';
|
||||
import { useDisableSoftFocus } from './useDisableSoftFocus';
|
||||
|
||||
export function useLeaveTableFocus() {
|
||||
const resetHotkeysScopeStack = useResetHotkeysScopeStack();
|
||||
const currentHotkeysScope = useCurrentHotkeysScope();
|
||||
|
||||
const disableSoftFocus = useDisableSoftFocus();
|
||||
const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode();
|
||||
|
||||
return async function leaveTableFocus() {
|
||||
if (currentHotkeysScope?.scope === InternalHotkeysScope.Table) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeCurrentCellInEditMode();
|
||||
disableSoftFocus();
|
||||
resetHotkeysScopeStack(InternalHotkeysScope.Table);
|
||||
};
|
||||
}
|
||||
@ -1,72 +1,74 @@
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useRemoveFromHotkeysScopeStack } from '@/hotkeys/hooks/useRemoveFromHotkeysScopeStack';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState';
|
||||
|
||||
import { useDisableSoftFocus } from './useDisableSoftFocus';
|
||||
import { useMoveSoftFocus } from './useMoveSoftFocus';
|
||||
|
||||
export function useMapKeyboardToSoftFocus() {
|
||||
const { moveDown, moveLeft, moveRight, moveUp } = useMoveSoftFocus();
|
||||
|
||||
const removeFromHotkeysScopedStack = useRemoveFromHotkeysScopeStack();
|
||||
const disableSoftFocus = useDisableSoftFocus();
|
||||
|
||||
const [isSomeInputInEditMode] = useRecoilState(isSomeInputInEditModeState);
|
||||
|
||||
useHotkeys(
|
||||
'up, shift+enter',
|
||||
useScopedHotkeys(
|
||||
[Key.ArrowUp, `${Key.Shift}+${Key.Enter}`],
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveUp();
|
||||
}
|
||||
},
|
||||
InternalHotkeysScope.TableSoftFocus,
|
||||
[moveUp, isSomeInputInEditMode],
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'down',
|
||||
useScopedHotkeys(
|
||||
Key.ArrowDown,
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveDown();
|
||||
}
|
||||
},
|
||||
InternalHotkeysScope.TableSoftFocus,
|
||||
[moveDown, isSomeInputInEditMode],
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
['left', 'shift+tab'],
|
||||
useScopedHotkeys(
|
||||
[Key.ArrowLeft, `${Key.Shift}+${Key.Tab}`],
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveLeft();
|
||||
}
|
||||
},
|
||||
InternalHotkeysScope.TableSoftFocus,
|
||||
[moveLeft, isSomeInputInEditMode],
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
},
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
['right', 'tab'],
|
||||
useScopedHotkeys(
|
||||
[Key.ArrowRight, Key.Tab],
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveRight();
|
||||
}
|
||||
},
|
||||
InternalHotkeysScope.TableSoftFocus,
|
||||
[moveRight, isSomeInputInEditMode],
|
||||
{
|
||||
preventDefault: true,
|
||||
enableOnContentEditable: true,
|
||||
enableOnFormTags: true,
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
removeFromHotkeysScopedStack(InternalHotkeysScope.TableSoftFocus);
|
||||
disableSoftFocus();
|
||||
},
|
||||
InternalHotkeysScope.TableSoftFocus,
|
||||
[removeFromHotkeysScopedStack, disableSoftFocus],
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { currentCellInEditModePositionState } from '../states/currentCellInEditModePositionState';
|
||||
import { isCellInEditModeFamilyState } from '../states/isCellInEditModeFamilyState';
|
||||
import { CellPosition } from '../types/CellPosition';
|
||||
|
||||
export function useMoveEditModeToCellPosition() {
|
||||
return useRecoilCallback(({ set, snapshot }) => {
|
||||
return (newPosition: CellPosition) => {
|
||||
const currentCellInEditModePosition = snapshot
|
||||
.getLoadable(currentCellInEditModePositionState)
|
||||
.valueOrThrow();
|
||||
|
||||
set(isCellInEditModeFamilyState(currentCellInEditModePosition), false);
|
||||
|
||||
set(currentCellInEditModePositionState, newPosition);
|
||||
|
||||
set(isCellInEditModeFamilyState(newPosition), true);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
@ -1,16 +1,19 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isSoftFocusActiveState } from '../states/isSoftFocusActiveState';
|
||||
import { isSoftFocusOnCellFamilyState } from '../states/isSoftFocusOnCellFamilyState';
|
||||
import { softFocusPositionState } from '../states/softFocusPositionState';
|
||||
import { TablePosition } from '../types/TablePosition';
|
||||
import { CellPosition } from '../types/CellPosition';
|
||||
|
||||
export function useSetSoftFocusPosition() {
|
||||
return useRecoilCallback(({ set, snapshot }) => {
|
||||
return (newPosition: TablePosition) => {
|
||||
return (newPosition: CellPosition) => {
|
||||
const currentPosition = snapshot
|
||||
.getLoadable(softFocusPositionState)
|
||||
.valueOrThrow();
|
||||
|
||||
set(isSoftFocusActiveState, true);
|
||||
|
||||
set(isSoftFocusOnCellFamilyState(currentPosition), false);
|
||||
|
||||
set(softFocusPositionState, newPosition);
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { CellPosition } from '../types/CellPosition';
|
||||
|
||||
export const currentCellInEditModePositionState = atom<CellPosition>({
|
||||
key: 'currentCellInEditModePositionState',
|
||||
default: {
|
||||
row: 0,
|
||||
column: 1,
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,8 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import { CellPosition } from '../types/CellPosition';
|
||||
|
||||
export const isCellInEditModeFamilyState = atomFamily<boolean, CellPosition>({
|
||||
key: 'isCellInEditModeFamilyState',
|
||||
default: false,
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const isSoftFocusActiveState = atom<boolean>({
|
||||
key: 'isSoftFocusActiveState',
|
||||
default: false,
|
||||
});
|
||||
@ -1,8 +1,8 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import { TablePosition } from '../types/TablePosition';
|
||||
import { CellPosition } from '../types/CellPosition';
|
||||
|
||||
export const isSoftFocusOnCellFamilyState = atomFamily<boolean, TablePosition>({
|
||||
export const isSoftFocusOnCellFamilyState = atomFamily<boolean, CellPosition>({
|
||||
key: 'isSoftFocusOnCellFamilyState',
|
||||
default: false,
|
||||
});
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { TablePosition } from '../types/TablePosition';
|
||||
import { CellPosition } from '../types/CellPosition';
|
||||
|
||||
export const softFocusPositionState = atom<TablePosition>({
|
||||
export const softFocusPositionState = atom<CellPosition>({
|
||||
key: 'softFocusPositionState',
|
||||
default: {
|
||||
row: 0,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export type TablePosition = {
|
||||
export type CellPosition = {
|
||||
row: number;
|
||||
column: number;
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { TablePosition } from '../TablePosition';
|
||||
import { CellPosition } from '../CellPosition';
|
||||
|
||||
export function isTablePosition(value: any): value is TablePosition {
|
||||
export function isTablePosition(value: any): value is CellPosition {
|
||||
return (
|
||||
value && typeof value.row === 'number' && typeof value.column === 'number'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user