Fix action menu dropdown (#8368)

Fix action menu dropdown not closing when clicking outside the table or
board and introduce helper functions to get the action menu component
ids.
This commit is contained in:
Raphaël Bosi
2024-11-06 16:11:31 +01:00
committed by GitHub
parent 278ab4c513
commit a6007d4376
21 changed files with 166 additions and 78 deletions

View File

@ -1,5 +1,7 @@
import { useRecoilCallback } from 'recoil';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
@ -8,14 +10,16 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
const { selectedRecordIdsSelector, isRecordBoardCardSelectedFamilyState } =
useRecordBoardStates(recordBoardId);
const isActionMenuDropdownOpenState = extractComponentState(
isDropdownOpenComponentState,
getActionMenuDropdownIdFromActionMenuId(
getActionMenuIdFromRecordIndexId(recordBoardId),
),
);
const resetRecordSelection = useRecoilCallback(
({ snapshot, set }) =>
() => {
const isActionMenuDropdownOpenState = extractComponentState(
isDropdownOpenComponentState,
`action-menu-dropdown-${recordBoardId}`,
);
set(isActionMenuDropdownOpenState, false);
const recordIds = snapshot
@ -27,7 +31,7 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
}
},
[
recordBoardId,
isActionMenuDropdownOpenState,
selectedRecordIdsSelector,
isRecordBoardCardSelectedFamilyState,
],

View File

@ -1,5 +1,7 @@
import { useActionMenu } from '@/action-menu/hooks/useActionMenu';
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
@ -183,14 +185,19 @@ export const RecordBoardCard = ({
RecordBoardScopeInternalContext,
);
const actionMenuId = getActionMenuIdFromRecordIndexId(recordBoardId);
const actionMenuDropdownId =
getActionMenuDropdownIdFromActionMenuId(actionMenuId);
const setActionMenuDropdownPosition = useSetRecoilState(
extractComponentState(
recordIndexActionMenuDropdownPositionComponentState,
`action-menu-dropdown-${recordBoardId}`,
actionMenuDropdownId,
),
);
const { openActionMenuDropdown } = useActionMenu(recordBoardId);
const { openActionMenuDropdown } = useActionMenu(actionMenuId);
const handleActionMenuDropdown = (event: React.MouseEvent) => {
event.preventDefault();

View File

@ -3,19 +3,28 @@ import { useRecoilCallback } from 'recoil';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { isSoftFocusActiveComponentState } from '@/object-record/record-table/states/isSoftFocusActiveComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useDisableSoftFocus } from './useDisableSoftFocus';
export const useLeaveTableFocus = (recordTableId?: string) => {
const disableSoftFocus = useDisableSoftFocus(recordTableId);
const isSoftFocusActiveState = useRecoilComponentCallbackStateV2(
isSoftFocusActiveComponentState,
const recordTableIdFromContext = useAvailableComponentInstanceIdOrThrow(
RecordTableComponentInstanceContext,
recordTableId,
);
const resetTableRowSelection = useResetTableRowSelection(recordTableId);
const disableSoftFocus = useDisableSoftFocus(recordTableIdFromContext);
const isSoftFocusActiveState = useRecoilComponentCallbackStateV2(
isSoftFocusActiveComponentState,
recordTableIdFromContext,
);
const resetTableRowSelection = useResetTableRowSelection(
recordTableIdFromContext,
);
return useRecoilCallback(
({ snapshot }) =>

View File

@ -1,25 +1,43 @@
import { useRecoilCallback } from 'recoil';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { tableRowIdsComponentState } from '@/object-record/record-table/states/tableRowIdsComponentState';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
export const useResetTableRowSelection = (recordTableId?: string) => {
const recordTableIdFromContext = useAvailableComponentInstanceIdOrThrow(
RecordTableComponentInstanceContext,
recordTableId,
);
const tableRowIdsState = useRecoilComponentCallbackStateV2(
tableRowIdsComponentState,
recordTableId,
recordTableIdFromContext,
);
const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2(
isRowSelectedComponentFamilyState,
recordTableId,
recordTableIdFromContext,
);
const hasUserSelectedAllRowsState = useRecoilComponentCallbackStateV2(
hasUserSelectedAllRowsComponentState,
recordTableId,
recordTableIdFromContext,
);
const isActionMenuDropdownOpenState = extractComponentState(
isDropdownOpenComponentState,
getActionMenuDropdownIdFromActionMenuId(
getActionMenuIdFromRecordIndexId(recordTableIdFromContext),
),
);
return useRecoilCallback(
@ -33,17 +51,12 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
set(hasUserSelectedAllRowsState, false);
const isActionMenuDropdownOpenState = extractComponentState(
isDropdownOpenComponentState,
`action-menu-dropdown-${recordTableId}`,
);
set(isActionMenuDropdownOpenState, false);
},
[
tableRowIdsState,
hasUserSelectedAllRowsState,
recordTableId,
isActionMenuDropdownOpenState,
isRowSelectedFamilyState,
],
);

View File

@ -16,6 +16,7 @@ import { ColumnDefinition } from '../types/ColumnDefinition';
import { TableHotkeyScope } from '../types/TableHotkeyScope';
import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { onColumnsChangeComponentState } from '@/object-record/record-table/states/onColumnsChangeComponentState';
import { onEntityCountChangeComponentState } from '@/object-record/record-table/states/onEntityCountChangeComponentState';
@ -27,6 +28,7 @@ import { tableFiltersComponentState } from '@/object-record/record-table/states/
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState';
import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useDisableSoftFocus } from './internal/useDisableSoftFocus';
@ -42,7 +44,10 @@ type useRecordTableProps = {
};
export const useRecordTable = (props?: useRecordTableProps) => {
const recordTableId = props?.recordTableId;
const recordTableId = useAvailableComponentInstanceIdOrThrow(
RecordTableComponentInstanceContext,
props?.recordTableId,
);
const availableTableColumnsState = useRecoilComponentCallbackStateV2(
availableTableColumnsComponentState,

View File

@ -16,7 +16,7 @@ export const RecordTableBodyUnselectEffect = ({
tableBodyRef,
recordTableId,
}: RecordTableBodyUnselectEffectProps) => {
const leaveTableFocus = useLeaveTableFocus();
const leaveTableFocus = useLeaveTableFocus(recordTableId);
const { resetTableRowSelection, useMapKeyboardToSoftFocus } = useRecordTable({
recordTableId,

View File

@ -2,6 +2,8 @@ import { useRecoilCallback } from 'recoil';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
import { getActionBarIdFromActionMenuId } from '@/action-menu/utils/getActionBarIdFromActionMenuId';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
@ -24,21 +26,29 @@ export const useTriggerActionMenuDropdown = ({
recordTableId,
);
const recordIndexActionMenuDropdownPositionState = extractComponentState(
recordIndexActionMenuDropdownPositionComponentState,
getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId),
);
const isActionMenuDropdownOpenState = extractComponentState(
isDropdownOpenComponentState,
getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId),
);
const isActionBarOpenState = isBottomBarOpenedComponentState.atomFamily({
instanceId: getActionBarIdFromActionMenuId(actionMenuInstanceId),
});
const triggerActionMenuDropdown = useRecoilCallback(
({ set, snapshot }) =>
(event: React.MouseEvent, recordId: string) => {
event.preventDefault();
set(
extractComponentState(
recordIndexActionMenuDropdownPositionComponentState,
`action-menu-dropdown-${actionMenuInstanceId}`,
),
{
x: event.clientX,
y: event.clientY,
},
);
set(recordIndexActionMenuDropdownPositionState, {
x: event.clientX,
y: event.clientY,
});
const isRowSelected = getSnapshotValue(
snapshot,
@ -49,21 +59,15 @@ export const useTriggerActionMenuDropdown = ({
set(isRowSelectedFamilyState(recordId), true);
}
const isActionMenuDropdownOpenState = extractComponentState(
isDropdownOpenComponentState,
`action-menu-dropdown-${actionMenuInstanceId}`,
);
const isActionBarOpenState = isBottomBarOpenedComponentState.atomFamily(
{
instanceId: `action-bar-${actionMenuInstanceId}`,
},
);
set(isActionBarOpenState, false);
set(isActionMenuDropdownOpenState, true);
},
[actionMenuInstanceId, isRowSelectedFamilyState],
[
isActionBarOpenState,
isActionMenuDropdownOpenState,
isRowSelectedFamilyState,
recordIndexActionMenuDropdownPositionState,
],
);
return { triggerActionMenuDropdown };