file-tree-item-inner.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { useEffect, createRef } from 'react'
  2. import PropTypes from 'prop-types'
  3. import classNames from 'classnames'
  4. import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed'
  5. import { useFileTreeMainContext } from '../../contexts/file-tree-main'
  6. import { useDraggable } from '../../contexts/file-tree-draggable'
  7. import FileTreeItemName from './file-tree-item-name'
  8. import FileTreeItemMenu from './file-tree-item-menu'
  9. import { useFileTreeSelectable } from '../../contexts/file-tree-selectable'
  10. function FileTreeItemInner({ id, name, isSelected, icons }) {
  11. const { hasWritePermissions, setContextMenuCoords } = useFileTreeMainContext()
  12. const { selectedEntityIds } = useFileTreeSelectable()
  13. const hasMenu =
  14. hasWritePermissions && isSelected && selectedEntityIds.size === 1
  15. const { isDragging, dragRef, setIsDraggable } = useDraggable(id)
  16. const itemRef = createRef()
  17. useEffect(() => {
  18. const item = itemRef.current
  19. if (isSelected && item) {
  20. // we're delaying scrolling due to a race condition with other elements,
  21. // mainly the Outline, being resized inside the same panel, causing the
  22. // FileTree to have its viewport shrinked after the selected item is
  23. // scrolled into the view, hiding it again.
  24. // See `left-pane-resize-all` in `file-tree-controller` for more information.
  25. setTimeout(() => {
  26. if (item) {
  27. scrollIntoViewIfNeeded(item, {
  28. scrollMode: 'if-needed',
  29. })
  30. }
  31. }, 100)
  32. }
  33. }, [isSelected, itemRef])
  34. function handleContextMenu(ev) {
  35. ev.preventDefault()
  36. setContextMenuCoords({
  37. top: ev.pageY,
  38. left: ev.pageX,
  39. })
  40. }
  41. return (
  42. <div
  43. className={classNames('entity', {
  44. 'dnd-draggable-dragging': isDragging,
  45. })}
  46. role="presentation"
  47. ref={dragRef}
  48. onContextMenu={handleContextMenu}
  49. >
  50. <div
  51. className="entity-name entity-name-react"
  52. role="presentation"
  53. ref={itemRef}
  54. >
  55. {icons}
  56. <FileTreeItemName
  57. name={name}
  58. isSelected={isSelected}
  59. setIsDraggable={setIsDraggable}
  60. />
  61. {hasMenu ? <FileTreeItemMenu id={id} /> : null}
  62. </div>
  63. </div>
  64. )
  65. }
  66. FileTreeItemInner.propTypes = {
  67. id: PropTypes.string.isRequired,
  68. name: PropTypes.string.isRequired,
  69. isSelected: PropTypes.bool.isRequired,
  70. icons: PropTypes.node,
  71. }
  72. export default FileTreeItemInner