import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { useRefWithAutoFocus } from '../../../../shared/hooks/use-ref-with-auto-focus'
import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
import { useFileTreeMainContext } from '../../contexts/file-tree-main'
function FileTreeItemName({ name, isSelected, setIsDraggable }) {
const { hasWritePermissions } = useFileTreeMainContext()
const {
isRenaming,
startRenaming,
finishRenaming,
error,
cancel,
} = useFileTreeActionable()
const isRenamingEntity = isRenaming && isSelected && !error
useEffect(() => {
setIsDraggable(hasWritePermissions && !isRenamingEntity)
}, [setIsDraggable, hasWritePermissions, isRenamingEntity])
if (isRenamingEntity) {
return (
)
}
return (
)
}
FileTreeItemName.propTypes = {
name: PropTypes.string.isRequired,
isSelected: PropTypes.bool.isRequired,
setIsDraggable: PropTypes.func.isRequired,
}
function DisplayName({ name, isSelected, startRenaming }) {
const [clicksInSelectedCount, setClicksInSelectedCount] = useState(0)
function onClick() {
setClicksInSelectedCount(clicksInSelectedCount + 1)
if (!isSelected) setClicksInSelectedCount(0)
}
function onDoubleClick() {
// only start renaming if the button got two or more clicks while the item
// was selected. This is to prevent starting a rename on an unselected item.
// When the item is being selected it can trigger a loss of focus which
// causes UI problems.
if (clicksInSelectedCount < 2) return
startRenaming()
}
return (
)
}
DisplayName.propTypes = {
name: PropTypes.string.isRequired,
startRenaming: PropTypes.func.isRequired,
isSelected: PropTypes.bool.isRequired,
}
function InputName({ initialValue, finishRenaming, cancel }) {
const [value, setValue] = useState(initialValue)
// The react-bootstrap Dropdown re-focuses on the Dropdown.Toggle
// after a menu item is clicked, following the ARIA authoring practices:
// https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-links.html
// To improve UX, we want to auto-focus to the input when renaming. We use
// requestAnimationFrame to immediately move focus to the input after it is
// shown
const { autoFocusedRef } = useRefWithAutoFocus()
function handleFocus(ev) {
const lastDotIndex = ev.target.value.lastIndexOf('.')
ev.target.setSelectionRange(0, lastDotIndex)
}
function handleChange(ev) {
setValue(ev.target.value)
}
function handleKeyDown(ev) {
if (ev.key === 'Enter') {
finishRenaming(value)
}
if (ev.key === 'Escape') {
cancel()
}
}
function handleBlur() {
finishRenaming(value)
}
return (
)
}
InputName.propTypes = {
initialValue: PropTypes.string.isRequired,
finishRenaming: PropTypes.func.isRequired,
cancel: PropTypes.func.isRequired,
}
export default FileTreeItemName