### Description Implement <ScrollRestoration /> ### Refs [https://github.com/twentyhq/twenty/issues/4357](https://github.com/twentyhq/twenty/issues/4183) ### Demo https://github.com/twentyhq/twenty/assets/140154534/321242e1-4751-4204-8c86-e9b921c1733e Fixes #4357 --------- Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: RubensRafael <rubensrafael2@live.com>
85 lines
2.2 KiB
TypeScript
85 lines
2.2 KiB
TypeScript
import { createContext, RefObject, useEffect, useRef } from 'react';
|
|
import styled from '@emotion/styled';
|
|
import { OverlayScrollbars } from 'overlayscrollbars';
|
|
import { useOverlayScrollbars } from 'overlayscrollbars-react';
|
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
|
|
|
import { overlayScrollbarsState } from '@/ui/utilities/scroll/states/overlayScrollbarsState';
|
|
import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState';
|
|
import { scrollTopState } from '@/ui/utilities/scroll/states/scrollTopState';
|
|
|
|
import 'overlayscrollbars/overlayscrollbars.css';
|
|
|
|
export const ScrollWrapperContext = createContext<RefObject<HTMLDivElement>>({
|
|
current: null,
|
|
});
|
|
|
|
const StyledScrollWrapper = styled.div`
|
|
display: flex;
|
|
height: 100%;
|
|
width: 100%;
|
|
|
|
.os-scrollbar-handle {
|
|
background-color: ${({ theme }) => theme.border.color.medium};
|
|
}
|
|
`;
|
|
|
|
export type ScrollWrapperProps = {
|
|
children: React.ReactNode;
|
|
className?: string;
|
|
hideY?: boolean;
|
|
hideX?: boolean;
|
|
};
|
|
|
|
export const ScrollWrapper = ({
|
|
children,
|
|
className,
|
|
hideX,
|
|
hideY,
|
|
}: ScrollWrapperProps) => {
|
|
const scrollableRef = useRef<HTMLDivElement>(null);
|
|
|
|
const handleScroll = useRecoilCallback(
|
|
({ set }) =>
|
|
(overlayScroll: OverlayScrollbars) => {
|
|
const target = overlayScroll.elements().scrollOffsetElement;
|
|
set(scrollTopState, target.scrollTop);
|
|
set(scrollLeftState, target.scrollLeft);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const setOverlayScrollbars = useSetRecoilState(overlayScrollbarsState);
|
|
|
|
const [initialize, instance] = useOverlayScrollbars({
|
|
options: {
|
|
scrollbars: { autoHide: 'scroll' },
|
|
overflow: {
|
|
y: hideY ? 'hidden' : undefined,
|
|
x: hideX ? 'hidden' : undefined,
|
|
},
|
|
},
|
|
events: {
|
|
scroll: handleScroll,
|
|
},
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (scrollableRef?.current !== null) {
|
|
initialize(scrollableRef.current);
|
|
}
|
|
}, [initialize, scrollableRef]);
|
|
|
|
useEffect(() => {
|
|
setOverlayScrollbars(instance());
|
|
}, [instance, setOverlayScrollbars]);
|
|
|
|
return (
|
|
<ScrollWrapperContext.Provider value={scrollableRef}>
|
|
<StyledScrollWrapper ref={scrollableRef} className={className}>
|
|
{children}
|
|
</StyledScrollWrapper>
|
|
</ScrollWrapperContext.Provider>
|
|
);
|
|
};
|