import { useState, useEffect, RefObject } from 'react' import { useRefWithAutoFocus } from '../../../../shared/hooks/use-ref-with-auto-focus' import { useFileTreeActionable } from '../../contexts/file-tree-actionable' function FileTreeItemName({ name, isSelected, setIsDraggable, }: { name: string isSelected: boolean setIsDraggable: (isDraggable: boolean) => void }) { const { isRenaming, startRenaming, finishRenaming, error, cancel } = useFileTreeActionable() const isRenamingEntity = isRenaming && isSelected && !error useEffect(() => { setIsDraggable(!isRenamingEntity) }, [setIsDraggable, isRenamingEntity]) if (isRenamingEntity) { return ( ) } return ( ) } function DisplayName({ name, isSelected, startRenaming, }: { name: string isSelected: boolean startRenaming: () => void }) { 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 ( ) } function InputName({ initialValue, finishRenaming, cancel, }: { initialValue: string finishRenaming: (value: string) => void cancel: () => void }) { 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: React.FocusEvent) { const lastDotIndex = ev.target.value.lastIndexOf('.') ev.target.setSelectionRange(0, lastDotIndex) } function handleChange(ev: React.ChangeEvent) { setValue(ev.target.value) } function handleKeyDown(ev: React.KeyboardEvent) { if (ev.key === 'Enter') { finishRenaming(value) } if (ev.key === 'Escape') { cancel() } } function handleBlur() { finishRenaming(value) } return ( } /> ) } export default FileTreeItemName