file-tree-folder.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { useEffect } from 'react'
  2. import classNames from 'classnames'
  3. import {
  4. useFileTreeSelectable,
  5. useSelectableEntity,
  6. } from '../contexts/file-tree-selectable'
  7. import { useDroppable } from '../contexts/file-tree-draggable'
  8. import FileTreeItemInner from './file-tree-item/file-tree-item-inner'
  9. import FileTreeFolderList from './file-tree-folder-list'
  10. import usePersistedState from '../../../shared/hooks/use-persisted-state'
  11. import { Folder } from '../../../../../types/folder'
  12. import { Doc } from '../../../../../types/doc'
  13. import { FileRef } from '../../../../../types/file-ref'
  14. import FileTreeFolderIcons from './file-tree-folder-icons'
  15. function FileTreeFolder({
  16. name,
  17. id,
  18. folders,
  19. docs,
  20. files,
  21. }: {
  22. name: string
  23. id: string
  24. folders: Folder[]
  25. docs: Doc[]
  26. files: FileRef[]
  27. }) {
  28. const { isSelected, props: selectableEntityProps } = useSelectableEntity(
  29. id,
  30. 'folder'
  31. )
  32. const { selectedEntityParentIds } = useFileTreeSelectable()
  33. const [expanded, setExpanded] = usePersistedState(
  34. `folder.${id}.expanded`,
  35. false
  36. )
  37. useEffect(() => {
  38. if (selectedEntityParentIds.has(id)) {
  39. setExpanded(true)
  40. }
  41. }, [id, selectedEntityParentIds, setExpanded])
  42. function handleExpandCollapseClick() {
  43. setExpanded(!expanded)
  44. }
  45. const { isOver: isOverRoot, dropRef: dropRefRoot } = useDroppable(id)
  46. const { isOver: isOverList, dropRef: dropRefList } = useDroppable(id)
  47. return (
  48. <>
  49. <li
  50. // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
  51. role="treeitem"
  52. // aria-selected is provided in selectableEntityProps
  53. {...selectableEntityProps}
  54. aria-expanded={expanded}
  55. aria-label={name}
  56. tabIndex={0}
  57. ref={dropRefRoot}
  58. className={classNames(selectableEntityProps.className, {
  59. 'dnd-droppable-hover': isOverRoot || isOverList,
  60. })}
  61. translate="no"
  62. >
  63. <FileTreeItemInner
  64. id={id}
  65. name={name}
  66. type="folder"
  67. isSelected={isSelected}
  68. icons={
  69. <FileTreeFolderIcons
  70. expanded={expanded}
  71. onExpandCollapseClick={handleExpandCollapseClick}
  72. />
  73. }
  74. />
  75. </li>
  76. {expanded ? (
  77. <FileTreeFolderList
  78. folders={folders}
  79. docs={docs}
  80. files={files}
  81. dropRef={dropRefList}
  82. />
  83. ) : null}
  84. </>
  85. )
  86. }
  87. export default FileTreeFolder