import React, { useCallback, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import PageContainer from '~/client/services/PageContainer'; import { blinkElem } from '~/client/util/blink-section-header'; import { addSmoothScrollEvent } from '~/client/util/smooth-scroll'; import loggerFactory from '~/utils/logger'; import { StickyStretchableScroller } from './StickyStretchableScroller'; import { withUnstatedContainers } from './UnstatedUtils'; // eslint-disable-next-line no-unused-vars const logger = loggerFactory('growi:TableOfContents'); /** * @author Yuki Takei * */ const TableOfContents = (props) => { const { pageContainer } = props; const { pageUser } = pageContainer.state; const isUserPage = pageUser != null; const [tocHtml, setTocHtml] = useState(''); const calcViewHeight = useCallback(() => { // calculate absolute top of '#revision-toc' element const parentElem = document.querySelector('.grw-side-contents-container'); const parentBottom = parentElem.getBoundingClientRect().bottom; const containerElem = document.querySelector('#revision-toc'); const containerTop = containerElem.getBoundingClientRect().top; const containerComputedStyle = getComputedStyle(containerElem); const containerPaddingTop = parseFloat(containerComputedStyle['padding-top']); // get smaller bottom line of window height - .system-version height - margin 5px) and containerTop let bottom = Math.min(window.innerHeight - 20 - 5, parentBottom); if (isUserPage) { // raise the bottom line by the height and margin-top of UserContentLinks bottom -= 45; } // bottom - revisionToc top return bottom - (containerTop + containerPaddingTop); }, [isUserPage]); useEffect(() => { const tocDom = document.getElementById('revision-toc-content'); const anchorsInToc = Array.from(tocDom.getElementsByTagName('a')); addSmoothScrollEvent(anchorsInToc, blinkElem); }, [tocHtml]); // set handler to render ToC useEffect(() => { const handler = html => setTocHtml(html); window.globalEmitter.on('renderTocHtml', handler); return function cleanup() { window.globalEmitter.removeListener('renderTocHtml', handler); }; }, []); return ( { tocHtml !== '' ? (
) : (
) } ); }; /** * Wrapper component for using unstated */ const TableOfContentsWrapper = withUnstatedContainers(TableOfContents, [PageContainer]); TableOfContents.propTypes = { pageContainer: PropTypes.instanceOf(PageContainer).isRequired, }; export default TableOfContentsWrapper;