TableOfContents.jsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import React, { useCallback, useEffect } from 'react';
  2. import PropTypes from 'prop-types';
  3. import loggerFactory from '@alias/logger';
  4. import { withTranslation } from 'react-i18next';
  5. import PageContainer from '../services/PageContainer';
  6. import NavigationContainer from '../services/NavigationContainer';
  7. import { withUnstatedContainers } from './UnstatedUtils';
  8. import TopOfTableContents from './TopOfTableContents';
  9. import StickyStretchableScroller from './StickyStretchableScroller';
  10. // eslint-disable-next-line no-unused-vars
  11. const logger = loggerFactory('growi:TableOfContents');
  12. /**
  13. * @author Yuki Takei <yuki@weseek.co.jp>
  14. *
  15. */
  16. const TableOfContents = (props) => {
  17. const { pageContainer, navigationContainer } = props;
  18. const calcViewHeight = useCallback(() => {
  19. // calculate absolute top of '#revision-toc' element
  20. const containerElem = document.querySelector('#revision-toc');
  21. const containerTop = containerElem.getBoundingClientRect().top;
  22. // window height - revisionToc top - .system-version - .grw-fab-container height - top-of-table-contents height
  23. return window.innerHeight - containerTop - 20 - 155 - 26;
  24. }, []);
  25. const { tocHtml } = pageContainer.state;
  26. // execute after generation toc html
  27. useEffect(() => {
  28. const tocDom = document.getElementById('revision-toc-content');
  29. const anchorsInToc = Array.from(tocDom.getElementsByTagName('a'));
  30. navigationContainer.addSmoothScrollEvent(anchorsInToc);
  31. }, [tocHtml, navigationContainer]);
  32. return (
  33. <>
  34. <TopOfTableContents />
  35. <StickyStretchableScroller
  36. contentsElemSelector=".revision-toc .markdownIt-TOC"
  37. stickyElemSelector="#revision-toc"
  38. calcViewHeightFunc={calcViewHeight}
  39. >
  40. <div
  41. id="revision-toc-content"
  42. className="revision-toc-content"
  43. // eslint-disable-next-line react/no-danger
  44. dangerouslySetInnerHTML={{
  45. __html: tocHtml,
  46. }}
  47. />
  48. </StickyStretchableScroller>
  49. </>
  50. );
  51. };
  52. /**
  53. * Wrapper component for using unstated
  54. */
  55. const TableOfContentsWrapper = withUnstatedContainers(TableOfContents, [PageContainer, NavigationContainer]);
  56. TableOfContents.propTypes = {
  57. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  58. navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
  59. };
  60. export default withTranslation()(TableOfContentsWrapper);