| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- import React, {
- useEffect, useCallback, FC, useRef, useState, useMemo, RefObject,
- } from 'react';
- import SimpleBar from 'simplebar-react';
- import StickyEvents from 'sticky-events';
- import { debounce } from 'throttle-debounce';
- import loggerFactory from '~/utils/logger';
- const logger = loggerFactory('growi:cli:StickyStretchableScroller');
- export type StickyStretchableScrollerProps = {
- stickyElemSelector: string,
- simplebarRef?: (ref: RefObject<SimpleBar>) => void,
- calcViewHeight?: (scrollElement: HTMLElement) => number,
- }
- /**
- * USAGE:
- *
- const calcViewHeight = useCallback(() => {
- const containerElem = document.querySelector('#sticky-elem');
- const containerTop = containerElem.getBoundingClientRect().top;
- // stretch to the bottom of window
- return window.innerHeight - containerTop;
- });
- return (
- <StickyStretchableScroller
- stickyElemSelector="#sticky-elem"
- calcViewHeight={calcViewHeight}
- >
- <div>
- ...
- </div>
- </StickyStretchableScroller>
- );
- */
- export const StickyStretchableScroller: FC<StickyStretchableScrollerProps> = (props) => {
- const {
- children, stickyElemSelector, calcViewHeight, simplebarRef: setSimplebarRef,
- } = props;
- const simplebarRef = useRef<SimpleBar>(null);
- const [simplebarMaxHeight, setSimplebarMaxHeight] = useState<number|undefined>();
- /**
- * Reset scrollbar
- */
- const resetScrollbar = useCallback(() => {
- if (simplebarRef.current == null || calcViewHeight == null) {
- return;
- }
- const scrollElement = simplebarRef.current.getScrollElement();
- const newHeight = calcViewHeight(scrollElement);
- logger.debug('Set new height to simplebar', newHeight);
- // set new height
- setSimplebarMaxHeight(newHeight);
- // reculculate
- simplebarRef.current.recalculate();
- }, [calcViewHeight]);
- const resetScrollbarDebounced = useMemo(() => debounce(100, resetScrollbar), [resetScrollbar]);
- // const stickyChangeHandler = useCallback(() => {
- // logger.debug('StickyEvents.CHANGE detected');
- // resetScrollbarDebounced();
- // }, [resetScrollbarDebounced]);
- // // setup effect by sticky event
- // useEffect(() => {
- // // sticky
- // // See: https://github.com/ryanwalters/sticky-events
- // const stickyEvents = new StickyEvents({ stickySelector: stickyElemSelector });
- // stickyEvents.enableEvents();
- // const { stickySelector } = stickyEvents;
- // const elem = document.querySelector(stickySelector);
- // elem.addEventListener(StickyEvents.CHANGE, stickyChangeHandler);
- // // return clean up handler
- // return () => {
- // elem.removeEventListener(StickyEvents.CHANGE, stickyChangeHandler);
- // };
- // }, [stickyElemSelector, stickyChangeHandler]);
- // setup effect by resizing event
- useEffect(() => {
- const resizeHandler = () => {
- resetScrollbarDebounced();
- };
- window.addEventListener('resize', resizeHandler);
- // return clean up handler
- return () => {
- window.removeEventListener('resize', resizeHandler);
- };
- }, [resetScrollbarDebounced]);
- // setup effect on init
- useEffect(() => {
- resetScrollbarDebounced();
- }, [resetScrollbarDebounced]);
- // update ref
- useEffect(() => {
- if (setSimplebarRef != null) {
- setSimplebarRef(simplebarRef);
- }
- }, [setSimplebarRef]);
- return (
- <SimpleBar style={{ maxHeight: simplebarMaxHeight }} ref={simplebarRef}>
- { children }
- </SimpleBar>
- );
- };
|