use-nested-outline.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { useEffect, useRef, useState } from 'react'
  2. import {
  3. FlatOutlineState,
  4. PartialFlatOutline,
  5. useOutlineContext,
  6. } from '@/features/ide-react/context/outline-context'
  7. import {
  8. nestOutline,
  9. Outline,
  10. } from '@/features/source-editor/utils/tree-operations/outline'
  11. import { debugConsole } from '@/utils/debugging'
  12. const outlineChanged = (
  13. a: PartialFlatOutline | undefined,
  14. b: PartialFlatOutline
  15. ): boolean => {
  16. if (!a) {
  17. return true
  18. }
  19. if (a.length !== b.length) {
  20. return true
  21. }
  22. for (let i = 0; i < a.length; i++) {
  23. const aItem = a[i]
  24. const bItem = b[i]
  25. if (
  26. aItem.level !== bItem.level ||
  27. aItem.line !== bItem.line ||
  28. aItem.title !== bItem.title
  29. ) {
  30. return true
  31. }
  32. }
  33. return false
  34. }
  35. export default function useNestedOutline() {
  36. const { flatOutline } = useOutlineContext()
  37. const [nestedOutline, setNestedOutline] = useState<{
  38. items: Outline[]
  39. partial: boolean
  40. }>(() => ({ items: [], partial: false }))
  41. const prevFlatOutlineRef = useRef<FlatOutlineState>(undefined)
  42. // when the flat outline changes, calculate the nested outline
  43. // TODO: only calculate when outlineExpanded is true
  44. useEffect(() => {
  45. const prevFlatOutline = prevFlatOutlineRef.current
  46. prevFlatOutlineRef.current = flatOutline
  47. if (flatOutline) {
  48. if (outlineChanged(prevFlatOutline?.items, flatOutline.items)) {
  49. debugConsole.log('Rebuilding changed outline')
  50. setNestedOutline({
  51. items: nestOutline(flatOutline.items),
  52. partial: flatOutline.partial,
  53. })
  54. }
  55. } else {
  56. setNestedOutline({ items: [], partial: false })
  57. }
  58. }, [flatOutline])
  59. return nestedOutline
  60. }