From a5323293e0996234d605ae5558620a0cb3fcef5d Mon Sep 17 00:00:00 2001 From: Hugh O'Brien Date: Tue, 9 Nov 2021 11:01:08 +0000 Subject: [PATCH] Merge pull request #5636 from overleaf/hb-single-context-menu-for-file-tree Use context menu for all file tree dropdowns GitOrigin-RevId: 8283093b428b4cb53bc1ed7795e398ffe4bd3496 --- .../file-tree-item/file-tree-item-inner.js | 1 + .../file-tree-item/file-tree-item-menu.js | 70 ++++++------------- .../stylesheets/app/editor/file-tree.less | 7 +- .../file-tree-item-inner.test.js | 5 +- .../file-tree-item-menu.test.js | 47 ------------- 5 files changed, 32 insertions(+), 98 deletions(-) delete mode 100644 services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-menu.test.js diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.js b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.js index 83e1a6f447..629331b703 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.js +++ b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.js @@ -42,6 +42,7 @@ function FileTreeItemInner({ id, name, isSelected, icons }) { function handleContextMenu(ev) { ev.preventDefault() + setContextMenuCoords({ top: ev.pageY, left: ev.pageX, diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu.js b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu.js index b30b75444d..ffa55083d8 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu.js +++ b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu.js @@ -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 ( - - + + ) } @@ -62,20 +52,4 @@ FileTreeItemMenu.propTypes = { id: PropTypes.string.isRequired, } -function Menu({ dropdownId, style, className }) { - return ( -
-
    - -
-
- ) -} - -Menu.propTypes = { - dropdownId: PropTypes.string.isRequired, - style: PropTypes.object, - className: PropTypes.string, -} - export default FileTreeItemMenu diff --git a/services/web/frontend/stylesheets/app/editor/file-tree.less b/services/web/frontend/stylesheets/app/editor/file-tree.less index 35cec90291..1ee70df00f 100644 --- a/services/web/frontend/stylesheets/app/editor/file-tree.less +++ b/services/web/frontend/stylesheets/app/editor/file-tree.less @@ -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; } } } diff --git a/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-inner.test.js b/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-inner.test.js index 274635d36a..94e68bd9a2 100644 --- a/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-inner.test.js +++ b/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-inner.test.js @@ -72,7 +72,10 @@ describe('', function () { it('starts rename on menu item click', function () { renderWithContext( - , + <> + + + , { contextProps: { rootDocId: '123abc', diff --git a/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-menu.test.js b/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-menu.test.js deleted file mode 100644 index d1637b621f..0000000000 --- a/services/web/test/frontend/features/file-tree/components/file-tree-item/file-tree-item-menu.test.js +++ /dev/null @@ -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('', function () { - const setContextMenuCoords = sinon.stub() - - afterEach(function () { - setContextMenuCoords.reset() - }) - - it('renders dropdown', function () { - renderWithContext( - - ) - - const toggleButton = screen.getByRole('button', { name: 'Menu' }) - fireEvent.click(toggleButton) - - screen.getByRole('menu') - }) - - it('open / close', function () { - renderWithContext( - - ) - - 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 }) - }) -})