From c90cf1eb8fa6fce731fd0ce528767876de5f74b0 Mon Sep 17 00:00:00 2001 From: David Pham Date: Sat, 21 Oct 2023 17:51:53 +0700 Subject: [PATCH] Fix issue 2126: DataTable '+' button dropdown positioning glitch (#2150) * Fix issue 2126: DataTable '+' button dropdown positioning glitch * Simplify code * Fix lint --------- Co-authored-by: Charles Bochet --- .../data-table/components/DataTableHeader.tsx | 62 ++++++++-------- .../components/DataTableHeaderPlusButton.tsx | 71 ------------------- .../DataTableHeaderPlusButtonContent.tsx | 50 +++++++++++++ .../menu-item/components/MenuItem.tsx | 2 +- 4 files changed, 80 insertions(+), 105 deletions(-) delete mode 100644 front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButton.tsx create mode 100644 front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButtonContent.tsx diff --git a/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx b/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx index 00d1815a0..304e69162 100644 --- a/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx +++ b/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx @@ -4,6 +4,8 @@ import { useRecoilCallback, useRecoilState } from 'recoil'; import { IconPlus } from '@/ui/display/icon'; import { IconButton } from '@/ui/input/button/components/IconButton'; +import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; +import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; @@ -16,7 +18,7 @@ import { visibleTableColumnsScopedSelector } from '../states/selectors/visibleTa import { tableColumnsScopedState } from '../states/tableColumnsScopedState'; import { ColumnHeadWithDropdown } from './ColumnHeadWithDropdown'; -import { DataTableHeaderPlusButton } from './DataTableHeaderPlusButton'; +import { DataTableHeaderPlusButtonContent } from './DataTableHeaderPlusButtonContent'; import { SelectAllCheckbox } from './SelectAllCheckbox'; const COLUMN_MIN_WIDTH = 104; @@ -58,18 +60,6 @@ const StyledResizeHandler = styled.div` z-index: 1; `; -const StyledAddIconButtonWrapper = styled.div` - display: inline-flex; - position: relative; -`; - -const StyledDataTableColumnMenu = styled(DataTableHeaderPlusButton)` - position: absolute; - right: 0; - top: 100%; - z-index: ${({ theme }) => theme.lastLayerZIndex}; -`; - const StyledTableHead = styled.thead` cursor: pointer; `; @@ -79,6 +69,12 @@ const StyledColumnHeadContainer = styled.div` z-index: 1; `; +const HIDDEN_TABLE_COLUMN_DROPDOWN_SCOPE_ID = + 'hidden-table-columns-dropdown-scope-id'; + +const HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID = + 'hidden-table-columns-dropdown-hotkey-scope-id'; + export const DataTableHeader = () => { const [resizeFieldOffset, setResizeFieldOffset] = useRecoilState( resizeFieldOffsetState, @@ -104,7 +100,6 @@ export const DataTableHeader = () => { number | null >(null); const [resizedFieldKey, setResizedFieldKey] = useState(null); - const [isColumnMenuOpen, setIsColumnMenuOpen] = useState(false); const { handleColumnsChange } = useTableColumns(); @@ -157,10 +152,6 @@ export const DataTableHeader = () => { onMouseUp: handleResizeHandlerEnd, }); - const toggleColumnMenu = useCallback(() => { - setIsColumnMenuOpen((previousValue) => !previousValue); - }, []); - const primaryColumn = visibleTableColumns[0]; return ( @@ -202,24 +193,29 @@ export const DataTableHeader = () => { /> ))} - {hiddenTableColumns.length > 0 && ( - - - {isColumnMenuOpen && ( - + + + } + dropdownComponents={} + dropdownPlacement="bottom-start" + dropdownHotkeyScope={{ + scope: HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID, + }} /> - )} - + + )} diff --git a/front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButton.tsx b/front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButton.tsx deleted file mode 100644 index 521dd7e7e..000000000 --- a/front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButton.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { ComponentProps, useCallback, useRef } from 'react'; -import styled from '@emotion/styled'; - -import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata'; -import { IconPlus } from '@/ui/display/icon'; -import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; -import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; -import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; - -import { useTableColumns } from '../hooks/useTableColumns'; -import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext'; -import { hiddenTableColumnsScopedSelector } from '../states/selectors/hiddenTableColumnsScopedSelector'; -import { ColumnDefinition } from '../types/ColumnDefinition'; - -const StyledHeaderPlusButton = styled(DropdownMenu)` - font-weight: ${({ theme }) => theme.font.weight.regular}; -`; - -type DataTableHeaderPlusButtonProps = { - onAddColumn?: () => void; - onClickOutside?: () => void; -} & ComponentProps<'div'>; - -export const DataTableHeaderPlusButton = ({ - onAddColumn, - onClickOutside = () => undefined, -}: DataTableHeaderPlusButtonProps) => { - const ref = useRef(null); - - const hiddenTableColumns = useRecoilScopedValue( - hiddenTableColumnsScopedSelector, - TableRecoilScopeContext, - ); - - useListenClickOutside({ - refs: [ref], - callback: onClickOutside, - }); - - const { handleColumnVisibilityChange } = useTableColumns(); - - const handleAddColumn = useCallback( - (column: ColumnDefinition) => { - onAddColumn?.(); - handleColumnVisibilityChange(column); - }, - [handleColumnVisibilityChange, onAddColumn], - ); - - return ( - - - {hiddenTableColumns.map((column) => ( - handleAddColumn(column), - }, - ]} - LeftIcon={column.Icon} - text={column.name} - /> - ))} - - - ); -}; diff --git a/front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButtonContent.tsx b/front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButtonContent.tsx new file mode 100644 index 000000000..d6d9a5b6a --- /dev/null +++ b/front/src/modules/ui/data/data-table/components/DataTableHeaderPlusButtonContent.tsx @@ -0,0 +1,50 @@ +import { useCallback } from 'react'; + +import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata'; +import { IconPlus } from '@/ui/display/icon'; +import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; +import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; +import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; +import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; + +import { useTableColumns } from '../hooks/useTableColumns'; +import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext'; +import { hiddenTableColumnsScopedSelector } from '../states/selectors/hiddenTableColumnsScopedSelector'; +import { ColumnDefinition } from '../types/ColumnDefinition'; + +export const DataTableHeaderPlusButtonContent = () => { + const { closeDropdown } = useDropdown(); + + const hiddenTableColumns = useRecoilScopedValue( + hiddenTableColumnsScopedSelector, + TableRecoilScopeContext, + ); + + const { handleColumnVisibilityChange } = useTableColumns(); + + const handleAddColumn = useCallback( + (column: ColumnDefinition) => { + closeDropdown(); + handleColumnVisibilityChange(column); + }, + [handleColumnVisibilityChange, closeDropdown], + ); + + return ( + + {hiddenTableColumns.map((column) => ( + handleAddColumn(column), + }, + ]} + LeftIcon={column.Icon} + text={column.name} + /> + ))} + + ); +}; diff --git a/front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx b/front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx index 17f7d7041..7ff390d74 100644 --- a/front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx +++ b/front/src/modules/ui/navigation/menu-item/components/MenuItem.tsx @@ -51,7 +51,7 @@ export const MenuItem = ({
{showIconButtons && ( - + )}