diff --git a/services/web/frontend/js/features/history/components/change-list/change-list.tsx b/services/web/frontend/js/features/history/components/change-list/change-list.tsx index d2906faf91..93613ce4e2 100644 --- a/services/web/frontend/js/features/history/components/change-list/change-list.tsx +++ b/services/web/frontend/js/features/history/components/change-list/change-list.tsx @@ -14,7 +14,10 @@ function ChangeList() { )} {!error && ( -
+
{labelsOnly ? : }
)} diff --git a/services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx b/services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx index 61fe196f40..48aee26017 100644 --- a/services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx +++ b/services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx @@ -1,42 +1,69 @@ -import { useState } from 'react' +import { useState, useRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { Dropdown } from 'react-bootstrap' import DropdownToggleWithTooltip from '../../../../../shared/components/dropdown/dropdown-toggle-with-tooltip' import Icon from '../../../../../shared/components/icon' +import DropdownMenuWithRef from '../../../../../shared/components/dropdown/dropdown-menu-with-ref' type DropdownMenuProps = { id: string children: React.ReactNode + parentSelector?: string } -function ActionsDropdown({ id, children }: DropdownMenuProps) { +function ActionsDropdown({ id, children, parentSelector }: DropdownMenuProps) { const { t } = useTranslation() const [isOpened, setIsOpened] = useState(false) + const menuRef = useRef() + + // handle the placement of the dropdown above or below the toggle button + useEffect(() => { + if (menuRef.current && parentSelector) { + const parent = menuRef.current.closest(parentSelector) + + if (!parent) { + return + } + + const parentBottom = parent.getBoundingClientRect().bottom + const { top, height } = menuRef.current.getBoundingClientRect() + + if (top + height > parentBottom) { + menuRef.current.style.bottom = '100%' + menuRef.current.style.top = 'auto' + } else { + menuRef.current.style.bottom = 'auto' + menuRef.current.style.top = '100%' + } + } + }) return ( - <> - setIsOpened(open)} + setIsOpened(open)} + > + - - - - - {children} - - - + + + + {children} + + ) } diff --git a/services/web/frontend/js/features/history/components/change-list/dropdown/history-version-dropdown.tsx b/services/web/frontend/js/features/history/components/change-list/dropdown/history-version-dropdown.tsx index f9f9f604f9..2c4849201d 100644 --- a/services/web/frontend/js/features/history/components/change-list/dropdown/history-version-dropdown.tsx +++ b/services/web/frontend/js/features/history/components/change-list/dropdown/history-version-dropdown.tsx @@ -22,7 +22,10 @@ function HistoryVersionDropdown({ updateMetaEndTimestamp, }: HistoryVersionDropdownProps) { return ( - + {!isComparing && !isSelected && ( diff --git a/services/web/frontend/js/features/history/components/change-list/dropdown/label-dropdown.tsx b/services/web/frontend/js/features/history/components/change-list/dropdown/label-dropdown.tsx index 8775c2a67b..573db42d69 100644 --- a/services/web/frontend/js/features/history/components/change-list/dropdown/label-dropdown.tsx +++ b/services/web/frontend/js/features/history/components/change-list/dropdown/label-dropdown.tsx @@ -20,7 +20,10 @@ function LabelDropdown({ updateMetaEndTimestamp, }: LabelDropdownProps) { return ( - + {!isComparing && !isSelected && ( , + { + children: React.ReactNode + bsRole: 'menu' + menuRef: React.MutableRefObject + className?: string + // The props below are passed by react-bootstrap + labelledBy?: string | undefined + rootCloseEvent?: 'click' | 'mousedown' | undefined + } +> + +const DropdownMenuWithRef = forwardRef< + HTMLUListElement, + DropdownMenuWithRefProps +>(function (props, ref) { + const { + children, + bsRole, + bsClass, + className, + open, + pullRight, + labelledBy, + menuRef, + onClose, + rootCloseEvent, + ...rest + } = props + + // expose the menu reference to both the `menuRef` and `ref callback` from react-bootstrap + const handleRefs = (node: HTMLUListElement) => { + if (typeof ref === 'function') { + ref(node) + } + menuRef.current = node + } + + // Implementation as suggested in + // https://react-bootstrap-v3.netlify.app/components/dropdowns/#btn-dropdowns-props-dropdown + return ( + +
    + {children} +
+
+ ) +}) +DropdownMenuWithRef.displayName = 'DropdownMenuWithRef' + +export default DropdownMenuWithRef diff --git a/services/web/frontend/js/shared/components/dropdown/dropdown-toggle-with-tooltip.tsx b/services/web/frontend/js/shared/components/dropdown/dropdown-toggle-with-tooltip.tsx index 5295b9790d..44756b6f16 100644 --- a/services/web/frontend/js/shared/components/dropdown/dropdown-toggle-with-tooltip.tsx +++ b/services/web/frontend/js/shared/components/dropdown/dropdown-toggle-with-tooltip.tsx @@ -5,7 +5,7 @@ import { DropdownProps } from 'react-bootstrap' import { MergeAndOverride } from '../../../../../types/utils' type CustomToggleProps = MergeAndOverride< - Pick, + Pick, { children: React.ReactNode bsRole: 'toggle' @@ -23,6 +23,7 @@ const DropdownToggleWithTooltip = forwardRef< children, bsClass, className, + open, bsRole: _bsRole, ...rest } = props @@ -33,6 +34,8 @@ const DropdownToggleWithTooltip = forwardRef< type="button" ref={ref} className={classnames(bsClass, 'btn', className)} + aria-expanded={open} + aria-haspopup="true" {...rest} > {children}