react-custom-scrollbars-2 icon indicating copy to clipboard operation
react-custom-scrollbars-2 copied to clipboard

[Enhancement] Pass some context to renderView

Open JesusTheHun opened this issue 4 years ago • 2 comments

Problem context

When rendering my view, I had an issue with the space occupied by the scrollbar. I do not want the scrollbar to hover my content, but I don't want to leave a blank space when there is no scrollbar.

Suggested solution

The renderView property is a simple react component React.StatelessComponent<any>. If you add a property for context it could open some rooms for several improvements :

interface ScrollbarsViewContext = { hasScrollbar: boolean; fullViewHeight: number; scrollbarWidth: number; scrollbarHeight: number; }

The first one clearly solves my problem, the others are just ideas from the top of my head.

JesusTheHun avatar Jan 05 '21 12:01 JesusTheHun

Fair enough. I don't have a lot of time, but if you are happy to work up a PR for this I'll take a look.

Depending on your browser requirements though a slider that sits outside the container may be easier and v.possible with native browser css rules

RobPethick avatar Apr 15 '21 13:04 RobPethick

I had the same issue, and I wish to share my solution.

I created a new wrapper component. Hopefully this will help others.

There is a bug with getValues() method, it will always return the same values for scrollHeight and clientHeight on the first render. So to fix this, I've added an init state value, which updates via the useEffect hook. This triggers the next useEffect hook which contains our value checking - if the scrollHeight is larger than the clientHeight then we set isScrollable to true.

Inside the renderView function, I'm adding the pr-4 class (this is a TailwindCSS class) to push the view away from the track.

This code contains customisation to the tracks. It also introduces 'pointer-events-none' (again, a TailwindCSS class) so that when the scrolling is active, the mouse pointer doesn't trigger any hover states on the content. Pretty nifty I think.


import React, {useState, useEffect, useRef} from 'react';
import {Scrollbars} from 'react-custom-scrollbars-2';
import classNames from 'classnames';

    const Scroll = (props) => {
        const vertTrackWidthChosen = '16px'; // Original is 6px
        const horzTrackHeightChosen = '16px'; // Original is 6px
    
        const [isSelectable, setIsSelectable] = useState(true);
        const [isScrollable, setIsScrollable] = useState(false);
    
        const scrollbars = useRef();
    
        const [init, setInit] = useState(false);
    
        useEffect(() => {
            const values = scrollbars.current.getValues();
            if (values?.scrollHeight > values?.clientHeight) setIsScrollable(true);
        }, [init]);
    
        useEffect(() => {
            setInit(true);
        }, []);
    
        return (
            <Scrollbars
                ref={scrollbars}
                hideTracksWhenNotNeeded
                onScrollStart={() => setIsSelectable(false)}
                onScrollStop={() => setIsSelectable(true)}
                {...props}
                renderThumbVertical={(props) => <div {...props} className="bg-green-300 rounded" />}
                renderView={({style, ...props}) => {
                    return (
                        <div
                            className={classNames('', {
                                'pr-4': isScrollable,
                            })}
                            style={style}
                            {...props}
                        />
                    );
                }}
                renderTrackHorizontal={({style, ...props}) => {
                    return <div {...props} className="" style={{...style, height: horzTrackHeightChosen}} />;
                }}
                renderTrackVertical={({style, ...props}) => {
                    return (
                        <div
                            {...props}
                            className="ml-16 top-0 bottom-0 right-0 p-0.5 bg-gray-900 bg-opacity-20"
                            style={{...style, width: vertTrackWidthChosen}}
                        />
                    );
                }}
            >
                <div
                    className={classNames('', {
                        'pointer-events-none': !isSelectable,
                    })}
                >
                    {props.children}
                </div>
            </Scrollbars>
        );
    };

Use it like this

<Scroll thumbSize={30}>
    _your content_
</Scroll>

stevenmunro avatar Aug 01 '21 04:08 stevenmunro