mirror of
https://github.com/overleaf/overleaf.git
synced 2025-01-11 16:34:28 +00:00
Merge pull request #13038 from overleaf/ii-history-react-dropdowns
[web] Adjust dropdowns placement in history list GitOrigin-RevId: 050e16b97630eb37c890ad9a97a56ba882cca06b
This commit is contained in:
parent
47f541690f
commit
32160a8c80
6 changed files with 139 additions and 28 deletions
|
@ -14,7 +14,10 @@ function ChangeList() {
|
|||
)}
|
||||
</div>
|
||||
{!error && (
|
||||
<div className="history-version-list-container">
|
||||
<div
|
||||
className="history-version-list-container"
|
||||
data-history-version-list-container
|
||||
>
|
||||
{labelsOnly ? <LabelsList /> : <AllHistoryList />}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -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<HTMLElement>()
|
||||
|
||||
// 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 (
|
||||
<>
|
||||
<Dropdown
|
||||
id={`history-version-dropdown-${id}`}
|
||||
pullRight
|
||||
open={isOpened}
|
||||
onToggle={open => setIsOpened(open)}
|
||||
<Dropdown
|
||||
id={`history-version-dropdown-${id}`}
|
||||
pullRight
|
||||
open={isOpened}
|
||||
onToggle={open => setIsOpened(open)}
|
||||
>
|
||||
<DropdownToggleWithTooltip
|
||||
bsRole="toggle"
|
||||
className="history-version-dropdown-menu-btn"
|
||||
tooltipProps={{
|
||||
id,
|
||||
description: t('more_actions'),
|
||||
overlayProps: { placement: 'bottom', trigger: ['hover'] },
|
||||
}}
|
||||
>
|
||||
<DropdownToggleWithTooltip
|
||||
bsRole="toggle"
|
||||
className="history-version-dropdown-menu-btn"
|
||||
tooltipProps={{
|
||||
id,
|
||||
description: t('more_actions'),
|
||||
overlayProps: { placement: 'bottom', trigger: ['hover'] },
|
||||
}}
|
||||
>
|
||||
<Icon type="ellipsis-v" accessibilityLabel={t('more_actions')} />
|
||||
</DropdownToggleWithTooltip>
|
||||
<Dropdown.Menu className="history-version-dropdown-menu">
|
||||
{children}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</>
|
||||
<Icon type="ellipsis-v" accessibilityLabel={t('more_actions')} />
|
||||
</DropdownToggleWithTooltip>
|
||||
<DropdownMenuWithRef
|
||||
bsRole="menu"
|
||||
className="history-version-dropdown-menu"
|
||||
menuRef={menuRef}
|
||||
>
|
||||
{children}
|
||||
</DropdownMenuWithRef>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,10 @@ function HistoryVersionDropdown({
|
|||
updateMetaEndTimestamp,
|
||||
}: HistoryVersionDropdownProps) {
|
||||
return (
|
||||
<ActionsDropdown id={id}>
|
||||
<ActionsDropdown
|
||||
id={id}
|
||||
parentSelector="[data-history-version-list-container]"
|
||||
>
|
||||
<AddLabel projectId={projectId} version={toV} />
|
||||
<Download projectId={projectId} version={toV} />
|
||||
{!isComparing && !isSelected && (
|
||||
|
|
|
@ -20,7 +20,10 @@ function LabelDropdown({
|
|||
updateMetaEndTimestamp,
|
||||
}: LabelDropdownProps) {
|
||||
return (
|
||||
<ActionsDropdown id={id}>
|
||||
<ActionsDropdown
|
||||
id={id}
|
||||
parentSelector="[data-history-version-list-container]"
|
||||
>
|
||||
<Download projectId={projectId} version={version} />
|
||||
{!isComparing && !isSelected && (
|
||||
<Compare
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import { forwardRef } from 'react'
|
||||
import classnames from 'classnames'
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import RootCloseWrapper from 'react-overlays/lib/RootCloseWrapper'
|
||||
import { DropdownProps } from 'react-bootstrap'
|
||||
import { MergeAndOverride } from '../../../../../types/utils'
|
||||
|
||||
type DropdownMenuWithRefProps = MergeAndOverride<
|
||||
Pick<DropdownProps, 'bsClass' | 'open' | 'pullRight' | 'onClose'>,
|
||||
{
|
||||
children: React.ReactNode
|
||||
bsRole: 'menu'
|
||||
menuRef: React.MutableRefObject<HTMLElement | undefined>
|
||||
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 (
|
||||
<RootCloseWrapper
|
||||
disabled={!open}
|
||||
onRootClose={onClose}
|
||||
event={rootCloseEvent}
|
||||
>
|
||||
<ul
|
||||
role={bsRole}
|
||||
className={classnames(className, bsClass, {
|
||||
'dropdown-menu-right': pullRight,
|
||||
})}
|
||||
aria-labelledby={labelledBy}
|
||||
ref={handleRefs}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
</RootCloseWrapper>
|
||||
)
|
||||
})
|
||||
DropdownMenuWithRef.displayName = 'DropdownMenuWithRef'
|
||||
|
||||
export default DropdownMenuWithRef
|
|
@ -5,7 +5,7 @@ import { DropdownProps } from 'react-bootstrap'
|
|||
import { MergeAndOverride } from '../../../../../types/utils'
|
||||
|
||||
type CustomToggleProps = MergeAndOverride<
|
||||
Pick<DropdownProps, 'bsClass'>,
|
||||
Pick<DropdownProps, 'bsClass' | 'open'>,
|
||||
{
|
||||
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}
|
||||
|
|
Loading…
Reference in a new issue