mirror of
https://github.com/overleaf/overleaf.git
synced 2025-03-02 23:23:38 +00:00
Merge pull request #5636 from overleaf/hb-single-context-menu-for-file-tree
Use context menu for all file tree dropdowns GitOrigin-RevId: 8283093b428b4cb53bc1ed7795e398ffe4bd3496
This commit is contained in:
parent
05c1ecdde0
commit
a5323293e0
5 changed files with 32 additions and 98 deletions
|
@ -42,6 +42,7 @@ function FileTreeItemInner({ id, name, isSelected, icons }) {
|
|||
|
||||
function handleContextMenu(ev) {
|
||||
ev.preventDefault()
|
||||
|
||||
setContextMenuCoords({
|
||||
top: ev.pageY,
|
||||
left: ev.pageX,
|
||||
|
|
|
@ -4,26 +4,30 @@ import PropTypes from 'prop-types'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import withoutPropagation from '../../../../infrastructure/without-propagation'
|
||||
|
||||
import { Dropdown, Overlay } from 'react-bootstrap'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import Icon from '../../../../shared/components/icon'
|
||||
|
||||
import FileTreeItemMenuItems from './file-tree-item-menu-items'
|
||||
import { useFileTreeMainContext } from '../../contexts/file-tree-main'
|
||||
|
||||
function FileTreeItemMenu({ id }) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false)
|
||||
const { contextMenuCoords, setContextMenuCoords } = useFileTreeMainContext()
|
||||
const [dropdownTarget, setDropdownTarget] = useState()
|
||||
|
||||
function handleToggle(wantOpen) {
|
||||
setDropdownOpen(wantOpen)
|
||||
function handleClick(_ev) {
|
||||
const target = dropdownTarget.getBoundingClientRect()
|
||||
if (!contextMenuCoords) {
|
||||
setContextMenuCoords({
|
||||
top: target.top + target.height / 2,
|
||||
left: target.right,
|
||||
})
|
||||
} else {
|
||||
setContextMenuCoords(null)
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
handleToggle(false)
|
||||
}
|
||||
|
||||
const toggleRef = component => {
|
||||
const menuButtonRef = component => {
|
||||
if (component) {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
setDropdownTarget(findDOMNode(component))
|
||||
|
@ -31,30 +35,16 @@ function FileTreeItemMenu({ id }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
onClick={withoutPropagation(handleClick)}
|
||||
pullRight
|
||||
open={dropdownOpen}
|
||||
id={`dropdown-${id}`}
|
||||
onToggle={handleToggle}
|
||||
>
|
||||
<Dropdown.Toggle
|
||||
noCaret
|
||||
className="dropdown-toggle-no-background entity-menu-toggle"
|
||||
onClick={withoutPropagation()}
|
||||
ref={toggleRef}
|
||||
<div className="menu-button btn-group">
|
||||
<Button
|
||||
className="entity-menu-toggle btn btn-default"
|
||||
id={`menu-button-${id}`}
|
||||
onClick={withoutPropagation(handleClick)}
|
||||
ref={menuButtonRef}
|
||||
>
|
||||
<Icon type="ellipsis-v" accessibilityLabel={t('menu')} />
|
||||
</Dropdown.Toggle>
|
||||
<Overlay
|
||||
bsRole="menu"
|
||||
show={dropdownOpen}
|
||||
target={dropdownTarget}
|
||||
container={document.body}
|
||||
>
|
||||
<Menu dropdownId={`dropdown-${id}`} />
|
||||
</Overlay>
|
||||
</Dropdown>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -62,20 +52,4 @@ FileTreeItemMenu.propTypes = {
|
|||
id: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
function Menu({ dropdownId, style, className }) {
|
||||
return (
|
||||
<div className={`dropdown open ${className}`} style={style}>
|
||||
<ul className="dropdown-menu" role="menu" aria-labelledby={dropdownId}>
|
||||
<FileTreeItemMenuItems />
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Menu.propTypes = {
|
||||
dropdownId: PropTypes.string.isRequired,
|
||||
style: PropTypes.object,
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
export default FileTreeItemMenu
|
||||
|
|
|
@ -155,7 +155,7 @@
|
|||
input {
|
||||
line-height: 1.6;
|
||||
}
|
||||
.dropdown-toggle > i {
|
||||
.entity-menu-toggle > i {
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
@ -242,7 +242,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
.menu-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
@ -306,6 +306,9 @@
|
|||
|
||||
.entity-menu-toggle {
|
||||
display: inline-block;
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,10 @@ describe('<FileTreeitemInner />', function () {
|
|||
|
||||
it('starts rename on menu item click', function () {
|
||||
renderWithContext(
|
||||
<FileTreeitemInner id="123abc" name="bar.tex" isSelected />,
|
||||
<>
|
||||
<FileTreeitemInner id="123abc" name="bar.tex" isSelected />
|
||||
<FileTreeContextMenu />
|
||||
</>,
|
||||
{
|
||||
contextProps: {
|
||||
rootDocId: '123abc',
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import sinon from 'sinon'
|
||||
import { expect } from 'chai'
|
||||
import { screen, fireEvent } from '@testing-library/react'
|
||||
import renderWithContext from '../../helpers/render-with-context'
|
||||
|
||||
import FileTreeitemMenu from '../../../../../../frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu'
|
||||
|
||||
describe('<FileTreeitemMenu />', function () {
|
||||
const setContextMenuCoords = sinon.stub()
|
||||
|
||||
afterEach(function () {
|
||||
setContextMenuCoords.reset()
|
||||
})
|
||||
|
||||
it('renders dropdown', function () {
|
||||
renderWithContext(
|
||||
<FileTreeitemMenu
|
||||
id="123abc"
|
||||
setContextMenuCoords={setContextMenuCoords}
|
||||
/>
|
||||
)
|
||||
|
||||
const toggleButton = screen.getByRole('button', { name: 'Menu' })
|
||||
fireEvent.click(toggleButton)
|
||||
|
||||
screen.getByRole('menu')
|
||||
})
|
||||
|
||||
it('open / close', function () {
|
||||
renderWithContext(
|
||||
<FileTreeitemMenu
|
||||
id="123abc"
|
||||
setContextMenuCoords={setContextMenuCoords}
|
||||
/>
|
||||
)
|
||||
|
||||
expect(screen.queryByRole('menu')).to.be.null
|
||||
|
||||
const toggleButton = screen.getByRole('button', { name: 'Menu' })
|
||||
|
||||
fireEvent.click(toggleButton)
|
||||
screen.getByRole('menu', { visible: true })
|
||||
|
||||
fireEvent.click(toggleButton)
|
||||
screen.getByRole('menu', { visible: false })
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue