Skip to content

Commit

Permalink
fix(app): Fix dropdown menu display issue for many items (#15420)
Browse files Browse the repository at this point in the history
* fix(app): Fix dropdown menu display issue for many items
  • Loading branch information
koji authored Jun 14, 2024
1 parent f0e1917 commit f5d585a
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 18 deletions.
17 changes: 9 additions & 8 deletions app/src/atoms/MenuList/DropdownMenu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { DropdownMenu as DropdownMenuComponent } from './DropdownMenu'
import type { Meta, StoryObj } from '@storybook/react'
import type { DropdownOption } from './DropdownMenu'

const mockOptions: DropdownOption[] = [
{ name: 'option 1', value: '1' },
{ name: 'option 2', value: '2' },
{ name: 'option 3', value: '3' },
{ name: 'option 4', value: '4' },
{ name: 'option 5', value: '5' },
{ name: 'option 6', value: '6' },
]
function createMockOptions(): DropdownOption[] {
const options: DropdownOption[] = []
for (let i = 1; i <= 100; i++) {
options.push({ name: `option ${i}`, value: `${i}` })
}
return options
}

const mockOptions: DropdownOption[] = createMockOptions()

const meta: Meta<typeof DropdownMenuComponent> = {
title: 'App/Atoms/DropdownMenu',
Expand Down
39 changes: 29 additions & 10 deletions app/src/atoms/MenuList/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ import {
useOnClickOutside,
POSITION_RELATIVE,
useHoverTooltip,
OVERFLOW_AUTO,
} from '@opentrons/components'
import { Tooltip } from '../Tooltip'
import { MenuItem } from './MenuItem'

/** this is the max height to display 10 items */
const MAX_HEIGHT = 316

/** this is for adjustment variable for the case that the space of the bottom and the space of the top are very close */
const HEIGHT_ADJUSTMENT = 100

export interface DropdownOption {
name: string
value: string
Expand Down Expand Up @@ -69,6 +76,12 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element {
'top' | 'bottom'
>('bottom')

const dropDownMenuWrapperRef = useOnClickOutside<HTMLDivElement>({
onClickOutside: () => {
setShowDropdownMenu(false)
},
})

React.useEffect(() => {
const handlePositionCalculation = (): void => {
const dropdownRect = dropDownMenuWrapperRef.current?.getBoundingClientRect()
Expand All @@ -88,10 +101,18 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element {
scrollOffset = parentRect.top
}

const dropdownBottom =
dropdownRect.bottom + (filterOptions.length + 1) * 34 - scrollOffset
const downSpace =
filterOptions.length + 1 > 10
? MAX_HEIGHT
: (filterOptions.length + 1) * 34
const dropdownBottom = dropdownRect.bottom + downSpace - scrollOffset

setDropdownPosition(dropdownBottom > availableHeight ? 'top' : 'bottom')
setDropdownPosition(
dropdownBottom > availableHeight &&
Math.abs(dropdownBottom - availableHeight) > HEIGHT_ADJUSTMENT
? 'top'
: 'bottom'
)
}
}

Expand All @@ -103,16 +124,11 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element {
window.removeEventListener('resize', handlePositionCalculation)
window.removeEventListener('scroll', handlePositionCalculation)
}
}, [filterOptions.length, window.innerHeight])
}, [filterOptions.length, dropDownMenuWrapperRef])

const toggleSetShowDropdownMenu = (): void => {
setShowDropdownMenu(!showDropdownMenu)
}
const dropDownMenuWrapperRef = useOnClickOutside<HTMLDivElement>({
onClickOutside: () => {
setShowDropdownMenu(false)
},
})

const DROPDOWN_STYLE = css`
flex-direction: ${DIRECTION_ROW};
Expand Down Expand Up @@ -204,7 +220,7 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element {
</Flex>
{showDropdownMenu && (
<Flex
zIndex={2}
zIndex={3}
borderRadius={BORDERS.borderRadius8}
boxShadow={BORDERS.tinyDropShadow}
position={POSITION_ABSOLUTE}
Expand All @@ -213,9 +229,12 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element {
width={width}
top={dropdownPosition === 'bottom' ? '2.5rem' : undefined}
bottom={dropdownPosition === 'top' ? '2.5rem' : undefined}
overflowY={OVERFLOW_AUTO}
maxHeight="20rem" // Set the maximum display number to 10.
>
{filterOptions.map((option, index) => (
<MenuItem
zIndex="3"
key={`${option.name}-${index}`}
onClick={() => {
onClick(option.value)
Expand Down

0 comments on commit f5d585a

Please sign in to comment.