List Scroll Jump

by Christian Micle

HTML

<div id="app"></div>

CSS

:root {
    scroll-behavior: smooth;
}

* {
    box-sizing: border-box;
}

html,
body,
#app {
  padding: 0;
  margin: 0;
  background-color: white;
  height: 100%;
}

.list {
  height: 100%;
  overflow: auto;
  box-sizing: border-box;
  overflow-anchor: none;
}

React

function chooseColor(index) {
    const v = index % 10;

    if (v === 0) {
        return 'purple';
    }

    if (v === 1) {
        return 'orange';
    }

    if (v === 2) {
        return 'green';
    }

    if (v === 3) {
        return 'yellow';
    }

    if (v === 4) {
        return 'magenta';
    }

    if (v === 5) {
        return 'red';
    }

    if (v === 6) {
        return 'black';
    }

    if (v === 7) {
        return 'brown';
    }

    if (v === 8) {
        return 'pink';
    }

    return 'cyan';
}

function List() {
    const listRef = React.useRef();
    const itemsRef = React.useRef();
    const itemsRemoved = React.useRef(false);
    const shiftInfoRef = React.useRef(null);

    const [itemsMeta, setItemsMeta] = React.useState({ from: { year: 1974, month: 3 }, to: { year: 1991, month: 8 }});

    const items = React.useMemo(() => {
        const builder = [];
        let startingMonth = itemsMeta.from.month;
        let endingMonth = 12;

        for (let yearCounter = itemsMeta.from.year; yearCounter <= itemsMeta.to.year; yearCounter += 1) {
            if (yearCounter === itemsMeta.to.year) {
                endingMonth = itemsMeta.to.month;
            }

            for (let monthCounter = startingMonth; monthCounter <= endingMonth; monthCounter += 1) {
                startingMonth = 1;

                const color = chooseColor(yearCounter);
              
                const text = yearCounter + ':' + monthCounter;

                builder.push(<div key={yearCounter * 12 + monthCounter}style={{color: 'white', fontSize: 48, margin: 20, backgroundColor: color}}>{text}</div>);
            }
        }

        return builder;
    }, [ itemsMeta ]);

    const handleScroll = React.useCallback(() => {
        const scrollOn = 140;

        const targetChild = itemsRef.current.childNodes[scrollOn];
        const item = itemsRef.current.childNodes[scrollOn + 1];

        const childRect = targetChild.getBoundingClientRect();
       ...