TableOfContents.jsx 2.3 KB

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