mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #3640 from overleaf/ta-file-tree-input-draggable
[ReactFileTree] Disable Draggable when Renaming Entity GitOrigin-RevId: 7241815d43791685453431aa95b8258ec17d3f81
This commit is contained in:
parent
dfffc76562
commit
b6eefe4e6e
4 changed files with 64 additions and 14 deletions
|
@ -16,7 +16,7 @@ function FileTreeItemInner({ id, name, isSelected, icons }) {
|
||||||
|
|
||||||
const hasMenu = hasWritePermissions && isSelected
|
const hasMenu = hasWritePermissions && isSelected
|
||||||
|
|
||||||
const { isDragging, dragRef } = useDraggable(id)
|
const { isDragging, dragRef, isDraggable, setIsDraggable } = useDraggable(id)
|
||||||
|
|
||||||
const itemRef = createRef()
|
const itemRef = createRef()
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ function FileTreeItemInner({ id, name, isSelected, icons }) {
|
||||||
role="presentation"
|
role="presentation"
|
||||||
ref={dragRef}
|
ref={dragRef}
|
||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
|
draggable={isDraggable}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="entity-name entity-name-react"
|
className="entity-name entity-name-react"
|
||||||
|
@ -61,7 +62,11 @@ function FileTreeItemInner({ id, name, isSelected, icons }) {
|
||||||
ref={itemRef}
|
ref={itemRef}
|
||||||
>
|
>
|
||||||
{icons}
|
{icons}
|
||||||
<FileTreeItemName name={name} isSelected={isSelected} />
|
<FileTreeItemName
|
||||||
|
name={name}
|
||||||
|
isSelected={isSelected}
|
||||||
|
setIsDraggable={setIsDraggable}
|
||||||
|
/>
|
||||||
{hasMenu ? <FileTreeItemMenu id={id} /> : null}
|
{hasMenu ? <FileTreeItemMenu id={id} /> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import { useRefWithAutoFocus } from '../../../../infrastructure/auto-focus'
|
import { useRefWithAutoFocus } from '../../../../infrastructure/auto-focus'
|
||||||
|
|
||||||
import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
|
import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
|
||||||
|
|
||||||
function FileTreeItemName({ name, isSelected }) {
|
function FileTreeItemName({ name, isSelected, setIsDraggable }) {
|
||||||
const {
|
const {
|
||||||
isRenaming,
|
isRenaming,
|
||||||
startRenaming,
|
startRenaming,
|
||||||
|
@ -16,6 +16,10 @@ function FileTreeItemName({ name, isSelected }) {
|
||||||
|
|
||||||
const isRenamingEntity = isRenaming && isSelected && !error
|
const isRenamingEntity = isRenaming && isSelected && !error
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsDraggable(!isRenamingEntity)
|
||||||
|
}, [setIsDraggable, isRenamingEntity])
|
||||||
|
|
||||||
if (isRenamingEntity) {
|
if (isRenamingEntity) {
|
||||||
return (
|
return (
|
||||||
<InputName
|
<InputName
|
||||||
|
@ -36,7 +40,8 @@ function FileTreeItemName({ name, isSelected }) {
|
||||||
|
|
||||||
FileTreeItemName.propTypes = {
|
FileTreeItemName.propTypes = {
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
isSelected: PropTypes.bool.isRequired
|
isSelected: PropTypes.bool.isRequired,
|
||||||
|
setIsDraggable: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
function DisplayName({ name, isSelected, startRenaming }) {
|
function DisplayName({ name, isSelected, startRenaming }) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useRef, useEffect } from 'react'
|
import React, { useRef, useEffect, useState } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
@ -78,6 +78,8 @@ export function useDraggable(draggedEntityId) {
|
||||||
const { fileTreeData } = useFileTreeMutable()
|
const { fileTreeData } = useFileTreeMutable()
|
||||||
const { selectedEntityIds } = useFileTreeSelectable()
|
const { selectedEntityIds } = useFileTreeSelectable()
|
||||||
|
|
||||||
|
const [isDraggable, setIsDraggable] = useState(true)
|
||||||
|
|
||||||
const item = { type: DRAGGABLE_TYPE }
|
const item = { type: DRAGGABLE_TYPE }
|
||||||
const [{ isDragging }, dragRef, preview] = useDrag({
|
const [{ isDragging }, dragRef, preview] = useDrag({
|
||||||
item, // required, but overwritten by the return value of `begin`
|
item, // required, but overwritten by the return value of `begin`
|
||||||
|
@ -104,7 +106,9 @@ export function useDraggable(draggedEntityId) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dragRef,
|
dragRef,
|
||||||
isDragging
|
isDragging,
|
||||||
|
isDraggable,
|
||||||
|
setIsDraggable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,38 @@ import renderWithContext from '../../helpers/render-with-context'
|
||||||
import FileTreeItemName from '../../../../../../frontend/js/features/file-tree/components/file-tree-item/file-tree-item-name'
|
import FileTreeItemName from '../../../../../../frontend/js/features/file-tree/components/file-tree-item/file-tree-item-name'
|
||||||
|
|
||||||
describe('<FileTreeItemName />', function() {
|
describe('<FileTreeItemName />', function() {
|
||||||
|
const setIsDraggable = sinon.stub()
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
global.requestAnimationFrame = sinon.stub()
|
global.requestAnimationFrame = sinon.stub()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
delete global.requestAnimationFrame
|
delete global.requestAnimationFrame
|
||||||
|
setIsDraggable.reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders name as button', function() {
|
it('renders name as button', function() {
|
||||||
renderWithContext(<FileTreeItemName name="foo.tex" isSelected />)
|
renderWithContext(
|
||||||
|
<FileTreeItemName
|
||||||
|
name="foo.tex"
|
||||||
|
isSelected
|
||||||
|
setIsDraggable={setIsDraggable}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
screen.getByRole('button', { name: 'foo.tex' })
|
screen.getByRole('button', { name: 'foo.tex' })
|
||||||
expect(screen.queryByRole('textbox')).to.not.exist
|
expect(screen.queryByRole('textbox')).to.not.exist
|
||||||
})
|
})
|
||||||
|
|
||||||
it("doesn't start renaming on unselected component", function() {
|
it("doesn't start renaming on unselected component", function() {
|
||||||
renderWithContext(<FileTreeItemName name="foo.tex" isSelected={false} />)
|
renderWithContext(
|
||||||
|
<FileTreeItemName
|
||||||
|
name="foo.tex"
|
||||||
|
isSelected={false}
|
||||||
|
setIsDraggable={setIsDraggable}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
const button = screen.queryByRole('button')
|
const button = screen.queryByRole('button')
|
||||||
fireEvent.click(button)
|
fireEvent.click(button)
|
||||||
|
@ -33,7 +48,13 @@ describe('<FileTreeItemName />', function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('start renaming on double-click', function() {
|
it('start renaming on double-click', function() {
|
||||||
renderWithContext(<FileTreeItemName name="foo.tex" isSelected />)
|
renderWithContext(
|
||||||
|
<FileTreeItemName
|
||||||
|
name="foo.tex"
|
||||||
|
isSelected
|
||||||
|
setIsDraggable={setIsDraggable}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
const button = screen.queryByRole('button')
|
const button = screen.queryByRole('button')
|
||||||
fireEvent.click(button)
|
fireEvent.click(button)
|
||||||
|
@ -42,12 +63,20 @@ describe('<FileTreeItemName />', function() {
|
||||||
screen.getByRole('textbox')
|
screen.getByRole('textbox')
|
||||||
expect(screen.queryByRole('button')).to.not.exist
|
expect(screen.queryByRole('button')).to.not.exist
|
||||||
expect(global.requestAnimationFrame).to.be.calledOnce
|
expect(global.requestAnimationFrame).to.be.calledOnce
|
||||||
|
expect(setIsDraggable).to.be.calledWith(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('cannot start renaming in read-only', function() {
|
it('cannot start renaming in read-only', function() {
|
||||||
renderWithContext(<FileTreeItemName name="foo.tex" isSelected />, {
|
renderWithContext(
|
||||||
contextProps: { hasWritePermissions: false }
|
<FileTreeItemName
|
||||||
})
|
name="foo.tex"
|
||||||
|
isSelected
|
||||||
|
setIsDraggable={setIsDraggable}
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
contextProps: { hasWritePermissions: false }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const button = screen.queryByRole('button')
|
const button = screen.queryByRole('button')
|
||||||
fireEvent.click(button)
|
fireEvent.click(button)
|
||||||
|
@ -59,7 +88,13 @@ describe('<FileTreeItemName />', function() {
|
||||||
|
|
||||||
describe('stop renaming', function() {
|
describe('stop renaming', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
renderWithContext(<FileTreeItemName name="foo.tex" isSelected />)
|
renderWithContext(
|
||||||
|
<FileTreeItemName
|
||||||
|
name="foo.tex"
|
||||||
|
isSelected
|
||||||
|
setIsDraggable={setIsDraggable}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
const button = screen.getByRole('button')
|
const button = screen.getByRole('button')
|
||||||
fireEvent.click(button)
|
fireEvent.click(button)
|
||||||
|
@ -75,6 +110,7 @@ describe('<FileTreeItemName />', function() {
|
||||||
fireEvent.keyDown(input, { key: 'Escape' })
|
fireEvent.keyDown(input, { key: 'Escape' })
|
||||||
|
|
||||||
screen.getByRole('button', { name: 'foo.tex' })
|
screen.getByRole('button', { name: 'foo.tex' })
|
||||||
|
expect(setIsDraggable).to.be.calledWith(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue