Created a specific scroll wrapper context per scroll wrapper and made ScrollTop and ScrollLeft componentStates (#6645)
@lucasbordeau @charlesBochet Issue #4826 Could u review this changes. Let me know what do you think. --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -46,7 +46,7 @@ export const EventList = ({ events, targetableObject }: EventListProps) => {
|
|||||||
const groupedEvents = groupEventsByMonth(filteredEvents);
|
const groupedEvents = groupEventsByMonth(filteredEvents);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollWrapper>
|
<ScrollWrapper contextProviderName="eventList">
|
||||||
<StyledTimelineContainer>
|
<StyledTimelineContainer>
|
||||||
{groupedEvents.map((group, index) => (
|
{groupedEvents.map((group, index) => (
|
||||||
<EventsGroup
|
<EventsGroup
|
||||||
|
|||||||
@ -349,7 +349,7 @@ export const CommandMenu = () => {
|
|||||||
)}
|
)}
|
||||||
</StyledInputContainer>
|
</StyledInputContainer>
|
||||||
<StyledList>
|
<StyledList>
|
||||||
<ScrollWrapper>
|
<ScrollWrapper contextProviderName="commandMenu">
|
||||||
<StyledInnerList isMobile={isMobile}>
|
<StyledInnerList isMobile={isMobile}>
|
||||||
<SelectableList
|
<SelectableList
|
||||||
selectableListId="command-menu-list"
|
selectableListId="command-menu-list"
|
||||||
|
|||||||
@ -148,7 +148,7 @@ export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => {
|
|||||||
>
|
>
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<StyledBoardHeader />
|
<StyledBoardHeader />
|
||||||
<ScrollWrapper>
|
<ScrollWrapper contextProviderName="recordBoard">
|
||||||
<StyledContainer ref={boardRef}>
|
<StyledContainer ref={boardRef}>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
{columnIds.map((columnId) => (
|
{columnIds.map((columnId) => (
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import { Checkbox, CheckboxVariant } from '@/ui/input/components/Checkbox';
|
|||||||
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
||||||
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||||
import { AnimatedEaseInOut } from '@/ui/utilities/animation/components/AnimatedEaseInOut';
|
import { AnimatedEaseInOut } from '@/ui/utilities/animation/components/AnimatedEaseInOut';
|
||||||
import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { RecordBoardScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
|
||||||
const StyledBoardCard = styled.div<{ selected: boolean }>`
|
const StyledBoardCard = styled.div<{ selected: boolean }>`
|
||||||
background-color: ${({ theme, selected }) =>
|
background-color: ${({ theme, selected }) =>
|
||||||
@ -199,10 +199,10 @@ export const RecordBoardCard = () => {
|
|||||||
return [updateEntity, { loading: false }];
|
return [updateEntity, { loading: false }];
|
||||||
};
|
};
|
||||||
|
|
||||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
const scrollWrapperRef = useContext(RecordBoardScrollWrapperContext);
|
||||||
|
|
||||||
const { ref: cardRef, inView } = useInView({
|
const { ref: cardRef, inView } = useInView({
|
||||||
root: scrollWrapperRef.current,
|
root: scrollWrapperRef?.ref.current,
|
||||||
rootMargin: '1000px',
|
rootMargin: '1000px',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -70,7 +70,7 @@ export const RecordTableWithWrappers = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
||||||
<ScrollWrapper>
|
<ScrollWrapper contextProviderName="recordTableWithWrappers">
|
||||||
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
||||||
<StyledTableWithHeader>
|
<StyledTableWithHeader>
|
||||||
<StyledTableContainer>
|
<StyledTableContainer>
|
||||||
|
|||||||
@ -10,8 +10,8 @@ import { useRecordTableStates } from '@/object-record/record-table/hooks/interna
|
|||||||
import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState';
|
import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState';
|
||||||
import { isRecordTableScrolledTopComponentState } from '@/object-record/record-table/states/isRecordTableScrolledTopComponentState';
|
import { isRecordTableScrolledTopComponentState } from '@/object-record/record-table/states/isRecordTableScrolledTopComponentState';
|
||||||
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
||||||
import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState';
|
import { useScrollLeftValue } from '@/ui/utilities/scroll/hooks/useScrollLeftValue';
|
||||||
import { scrollTopState } from '@/ui/utilities/scroll/states/scrollTopState';
|
import { useScrollTopValue } from '@/ui/utilities/scroll/hooks/useScrollTopValue';
|
||||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
||||||
@ -38,7 +38,7 @@ export const RecordTableBodyEffect = () => {
|
|||||||
|
|
||||||
const tableLastRowVisible = useRecoilValue(tableLastRowVisibleState);
|
const tableLastRowVisible = useRecoilValue(tableLastRowVisibleState);
|
||||||
|
|
||||||
const scrollTop = useRecoilValue(scrollTopState);
|
const scrollTop = useScrollTopValue('recordTableWithWrappers');
|
||||||
const setIsRecordTableScrolledTop = useSetRecoilComponentState(
|
const setIsRecordTableScrolledTop = useSetRecoilComponentState(
|
||||||
isRecordTableScrolledTopComponentState,
|
isRecordTableScrolledTopComponentState,
|
||||||
);
|
);
|
||||||
@ -57,7 +57,7 @@ export const RecordTableBodyEffect = () => {
|
|||||||
}
|
}
|
||||||
}, [scrollTop, setIsRecordTableScrolledTop]);
|
}, [scrollTop, setIsRecordTableScrolledTop]);
|
||||||
|
|
||||||
const scrollLeft = useRecoilValue(scrollLeftState);
|
const scrollLeft = useScrollLeftValue('recordTableWithWrappers');
|
||||||
|
|
||||||
const setIsRecordTableScrolledLeft = useSetRecoilComponentState(
|
const setIsRecordTableScrolledLeft = useSetRecoilComponentState(
|
||||||
isRecordTableScrolledLeftComponentState,
|
isRecordTableScrolledLeftComponentState,
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useInView } from 'react-intersection-observer';
|
import { useInView } from 'react-intersection-observer';
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
import { GRAY_SCALE } from 'twenty-ui';
|
import { GRAY_SCALE } from 'twenty-ui';
|
||||||
|
|
||||||
import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
|
import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
||||||
import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
|
||||||
type RecordTableBodyFetchMoreLoaderProps = {
|
type RecordTableBodyFetchMoreLoaderProps = {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
@ -40,12 +40,14 @@ export const RecordTableBodyFetchMoreLoader = ({
|
|||||||
[setRecordTableLastRowVisible],
|
[setRecordTableLastRowVisible],
|
||||||
);
|
);
|
||||||
|
|
||||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
const scrollWrapperRef = useContext(
|
||||||
|
RecordTableWithWrappersScrollWrapperContext,
|
||||||
|
);
|
||||||
|
|
||||||
const { ref: tbodyRef } = useInView({
|
const { ref: tbodyRef } = useInView({
|
||||||
onChange: onLastRowVisible,
|
onChange: onLastRowVisible,
|
||||||
rootMargin: '1000px',
|
rootMargin: '1000px',
|
||||||
root: scrollWrapperRef.current?.querySelector(
|
root: scrollWrapperRef?.ref.current?.querySelector(
|
||||||
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
|
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -54,11 +54,11 @@ const HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID =
|
|||||||
export const RecordTableHeaderLastColumn = () => {
|
export const RecordTableHeaderLastColumn = () => {
|
||||||
const { theme } = useContext(ThemeContext);
|
const { theme } = useContext(ThemeContext);
|
||||||
|
|
||||||
const scrollWrapper = useScrollWrapperScopedRef();
|
const scrollWrapper = useScrollWrapperScopedRef('recordTableWithWrappers');
|
||||||
|
|
||||||
const isTableWiderThanScreen =
|
const isTableWiderThanScreen =
|
||||||
(scrollWrapper.current?.clientWidth ?? 0) <
|
(scrollWrapper.ref.current?.clientWidth ?? 0) <
|
||||||
(scrollWrapper.current?.scrollWidth ?? 0);
|
(scrollWrapper.ref.current?.scrollWidth ?? 0);
|
||||||
|
|
||||||
const { hiddenTableColumnsSelector } = useRecordTableStates();
|
const { hiddenTableColumnsSelector } = useRecordTableStates();
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { RecordTableContext } from '@/object-record/record-table/contexts/Record
|
|||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
||||||
import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
|
||||||
export const RecordTableRowWrapper = ({
|
export const RecordTableRowWrapper = ({
|
||||||
recordId,
|
recordId,
|
||||||
@ -31,10 +31,12 @@ export const RecordTableRowWrapper = ({
|
|||||||
const { isRowSelectedFamilyState } = useRecordTableStates();
|
const { isRowSelectedFamilyState } = useRecordTableStates();
|
||||||
const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId));
|
const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId));
|
||||||
|
|
||||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
const scrollWrapperRef = useContext(
|
||||||
|
RecordTableWithWrappersScrollWrapperContext,
|
||||||
|
);
|
||||||
|
|
||||||
const { ref: elementRef, inView } = useInView({
|
const { ref: elementRef, inView } = useInView({
|
||||||
root: scrollWrapperRef.current?.querySelector(
|
root: scrollWrapperRef.ref.current?.querySelector(
|
||||||
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
|
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
|
||||||
),
|
),
|
||||||
rootMargin: '1000px',
|
rootMargin: '1000px',
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export const SettingsPageContainer = ({
|
|||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) => (
|
}) => (
|
||||||
<StyledScrollWrapper>
|
<StyledScrollWrapper contextProviderName="settingsPageContainer">
|
||||||
<StyledSettingsPageContainer>{children}</StyledSettingsPageContainer>
|
<StyledSettingsPageContainer>{children}</StyledSettingsPageContainer>
|
||||||
</StyledScrollWrapper>
|
</StyledScrollWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export const DropdownMenuItemsContainer = ({
|
|||||||
return (
|
return (
|
||||||
<StyledDropdownMenuItemsExternalContainer hasMaxHeight={hasMaxHeight}>
|
<StyledDropdownMenuItemsExternalContainer hasMaxHeight={hasMaxHeight}>
|
||||||
{hasMaxHeight ? (
|
{hasMaxHeight ? (
|
||||||
<StyledScrollWrapper>
|
<StyledScrollWrapper contextProviderName="dropdownMenuItemsContainer">
|
||||||
<StyledDropdownMenuItemsInternalContainer>
|
<StyledDropdownMenuItemsInternalContainer>
|
||||||
{children}
|
{children}
|
||||||
</StyledDropdownMenuItemsInternalContainer>
|
</StyledDropdownMenuItemsInternalContainer>
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export const ShowPageContainer = ({ children }: ShowPageContainerProps) => {
|
|||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
return isMobile ? (
|
return isMobile ? (
|
||||||
<StyledOuterContainer>
|
<StyledOuterContainer>
|
||||||
<StyledScrollWrapper>
|
<StyledScrollWrapper contextProviderName="showPageContainer">
|
||||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||||
</StyledScrollWrapper>
|
</StyledScrollWrapper>
|
||||||
</StyledOuterContainer>
|
</StyledOuterContainer>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
@ -46,7 +46,7 @@ export const ShowPageLeftContainer = ({
|
|||||||
{children}
|
{children}
|
||||||
</StyledInnerContainer>
|
</StyledInnerContainer>
|
||||||
) : (
|
) : (
|
||||||
<ScrollWrapper>
|
<ScrollWrapper contextProviderName="showPageLeftContainer">
|
||||||
<StyledIntermediateContainer>
|
<StyledIntermediateContainer>
|
||||||
<StyledInnerContainer isMobile={isMobile}>
|
<StyledInnerContainer isMobile={isMobile}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import * as React from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { IconComponent } from 'twenty-ui';
|
import { IconComponent } from 'twenty-ui';
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ export const TabList = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<TabListScope tabListScopeId={tabListId}>
|
<TabListScope tabListScopeId={tabListId}>
|
||||||
<ScrollWrapper hideY>
|
<ScrollWrapper hideY contextProviderName="tabList">
|
||||||
<StyledContainer className={className}>
|
<StyledContainer className={className}>
|
||||||
{tabs
|
{tabs
|
||||||
.filter((tab) => !tab.hide)
|
.filter((tab) => !tab.hide)
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
import { createContext, RefObject, useEffect, useRef } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { OverlayScrollbars } from 'overlayscrollbars';
|
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||||
import { useOverlayScrollbars } from 'overlayscrollbars-react';
|
import { useOverlayScrollbars } from 'overlayscrollbars-react';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ContextProviderName,
|
||||||
|
getContextByProviderName,
|
||||||
|
} from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
import { useScrollStates } from '@/ui/utilities/scroll/hooks/internal/useScrollStates';
|
||||||
import { overlayScrollbarsState } from '@/ui/utilities/scroll/states/overlayScrollbarsState';
|
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';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
|
|
||||||
export const ScrollWrapperContext = createContext<RefObject<HTMLDivElement>>({
|
|
||||||
current: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const StyledScrollWrapper = styled.div`
|
const StyledScrollWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -29,6 +28,7 @@ export type ScrollWrapperProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
hideY?: boolean;
|
hideY?: boolean;
|
||||||
hideX?: boolean;
|
hideX?: boolean;
|
||||||
|
contextProviderName: ContextProviderName;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScrollWrapper = ({
|
export const ScrollWrapper = ({
|
||||||
@ -36,18 +36,21 @@ export const ScrollWrapper = ({
|
|||||||
className,
|
className,
|
||||||
hideX,
|
hideX,
|
||||||
hideY,
|
hideY,
|
||||||
|
contextProviderName,
|
||||||
}: ScrollWrapperProps) => {
|
}: ScrollWrapperProps) => {
|
||||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||||
|
const Context = getContextByProviderName(contextProviderName);
|
||||||
|
|
||||||
const handleScroll = useRecoilCallback(
|
const { scrollTopComponentState, scrollLeftComponentState } =
|
||||||
({ set }) =>
|
useScrollStates(contextProviderName);
|
||||||
(overlayScroll: OverlayScrollbars) => {
|
const setScrollTop = useSetRecoilState(scrollTopComponentState);
|
||||||
const target = overlayScroll.elements().scrollOffsetElement;
|
const setScrollLeft = useSetRecoilState(scrollLeftComponentState);
|
||||||
set(scrollTopState, target.scrollTop);
|
|
||||||
set(scrollLeftState, target.scrollLeft);
|
const handleScroll = (overlayScroll: OverlayScrollbars) => {
|
||||||
},
|
const target = overlayScroll.elements().scrollOffsetElement;
|
||||||
[],
|
setScrollTop(target.scrollTop);
|
||||||
);
|
setScrollLeft(target.scrollLeft);
|
||||||
|
};
|
||||||
|
|
||||||
const setOverlayScrollbars = useSetRecoilState(overlayScrollbarsState);
|
const setOverlayScrollbars = useSetRecoilState(overlayScrollbarsState);
|
||||||
|
|
||||||
@ -75,10 +78,10 @@ export const ScrollWrapper = ({
|
|||||||
}, [instance, setOverlayScrollbars]);
|
}, [instance, setOverlayScrollbars]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollWrapperContext.Provider value={scrollableRef}>
|
<Context.Provider value={{ ref: scrollableRef, id: contextProviderName }}>
|
||||||
<StyledScrollWrapper ref={scrollableRef} className={className}>
|
<StyledScrollWrapper ref={scrollableRef} className={className}>
|
||||||
{children}
|
{children}
|
||||||
</StyledScrollWrapper>
|
</StyledScrollWrapper>
|
||||||
</ScrollWrapperContext.Provider>
|
</Context.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,78 @@
|
|||||||
|
import { createContext, RefObject } from 'react';
|
||||||
|
|
||||||
|
type ScrollWrapperContextValue = {
|
||||||
|
ref: RefObject<HTMLDivElement>;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContextProviderName =
|
||||||
|
| 'eventList'
|
||||||
|
| 'commandMenu'
|
||||||
|
| 'recordBoard'
|
||||||
|
| 'recordTableWithWrappers'
|
||||||
|
| 'settingsPageContainer'
|
||||||
|
| 'dropdownMenuItemsContainer'
|
||||||
|
| 'showPageContainer'
|
||||||
|
| 'showPageLeftContainer'
|
||||||
|
| 'tabList'
|
||||||
|
| 'releases'
|
||||||
|
| 'test';
|
||||||
|
|
||||||
|
const createScrollWrapperContext = (id: string) =>
|
||||||
|
createContext<ScrollWrapperContextValue>({
|
||||||
|
ref: { current: null },
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const EventListScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('eventList');
|
||||||
|
export const CommandMenuScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('commandMenu');
|
||||||
|
export const RecordBoardScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('recordBoard');
|
||||||
|
export const RecordTableWithWrappersScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('recordTableWithWrappers');
|
||||||
|
export const SettingsPageContainerScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('settingsPageContainer');
|
||||||
|
export const DropdownMenuItemsContainerScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('dropdownMenuItemsContainer');
|
||||||
|
export const ShowPageContainerScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('showPageContainer');
|
||||||
|
export const ShowPageLeftContainerScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('showPageLeftContainer');
|
||||||
|
export const TabListScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('tabList');
|
||||||
|
export const ReleasesScrollWrapperContext =
|
||||||
|
createScrollWrapperContext('releases');
|
||||||
|
export const TestScrollWrapperContext = createScrollWrapperContext('test');
|
||||||
|
|
||||||
|
export const getContextByProviderName = (
|
||||||
|
contextProviderName: ContextProviderName,
|
||||||
|
) => {
|
||||||
|
switch (contextProviderName) {
|
||||||
|
case 'eventList':
|
||||||
|
return EventListScrollWrapperContext;
|
||||||
|
case 'commandMenu':
|
||||||
|
return CommandMenuScrollWrapperContext;
|
||||||
|
case 'recordBoard':
|
||||||
|
return RecordBoardScrollWrapperContext;
|
||||||
|
case 'recordTableWithWrappers':
|
||||||
|
return RecordTableWithWrappersScrollWrapperContext;
|
||||||
|
case 'settingsPageContainer':
|
||||||
|
return SettingsPageContainerScrollWrapperContext;
|
||||||
|
case 'dropdownMenuItemsContainer':
|
||||||
|
return DropdownMenuItemsContainerScrollWrapperContext;
|
||||||
|
case 'showPageContainer':
|
||||||
|
return ShowPageContainerScrollWrapperContext;
|
||||||
|
case 'showPageLeftContainer':
|
||||||
|
return ShowPageLeftContainerScrollWrapperContext;
|
||||||
|
case 'tabList':
|
||||||
|
return TabListScrollWrapperContext;
|
||||||
|
case 'releases':
|
||||||
|
return ReleasesScrollWrapperContext;
|
||||||
|
case 'test':
|
||||||
|
return TestScrollWrapperContext;
|
||||||
|
default:
|
||||||
|
throw new Error('Context Provider not available');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -12,7 +12,7 @@ jest.mock('react', () => {
|
|||||||
|
|
||||||
describe('useScrollWrapperScopedRef', () => {
|
describe('useScrollWrapperScopedRef', () => {
|
||||||
it('should return the scrollWrapperRef if available', () => {
|
it('should return the scrollWrapperRef if available', () => {
|
||||||
const { result } = renderHook(() => useScrollWrapperScopedRef());
|
const { result } = renderHook(() => useScrollWrapperScopedRef('test'));
|
||||||
|
|
||||||
expect(result.current).toBeDefined();
|
expect(result.current).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
ContextProviderName,
|
||||||
|
getContextByProviderName,
|
||||||
|
} from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
import { scrollLeftComponentState } from '@/ui/utilities/scroll/states/scrollLeftComponentState';
|
||||||
|
import { scrollTopComponentState } from '@/ui/utilities/scroll/states/scrollTopComponentState';
|
||||||
|
|
||||||
|
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||||
|
|
||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
export const useScrollStates = (contextProviderName: ContextProviderName) => {
|
||||||
|
const Context = getContextByProviderName(contextProviderName);
|
||||||
|
const context = useContext(Context);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('Context not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id: scopeId } = context;
|
||||||
|
|
||||||
|
return {
|
||||||
|
scrollLeftComponentState: extractComponentState(
|
||||||
|
scrollLeftComponentState,
|
||||||
|
scopeId,
|
||||||
|
),
|
||||||
|
scrollTopComponentState: extractComponentState(
|
||||||
|
scrollTopComponentState,
|
||||||
|
scopeId,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { ContextProviderName } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
import { useScrollStates } from '@/ui/utilities/scroll/hooks/internal/useScrollStates';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useScrollLeftValue = (
|
||||||
|
contextProviderName: ContextProviderName,
|
||||||
|
) => {
|
||||||
|
const { scrollLeftComponentState } = useScrollStates(contextProviderName);
|
||||||
|
return useRecoilValue(scrollLeftComponentState);
|
||||||
|
};
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { ContextProviderName } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
import { useScrollStates } from '@/ui/utilities/scroll/hooks/internal/useScrollStates';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useScrollTopValue = (contextProviderName: ContextProviderName) => {
|
||||||
|
const { scrollTopComponentState } = useScrollStates(contextProviderName);
|
||||||
|
return useRecoilValue(scrollTopComponentState);
|
||||||
|
};
|
||||||
@ -2,10 +2,16 @@ import { useContext } from 'react';
|
|||||||
|
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
|
|
||||||
import { ScrollWrapperContext } from '../components/ScrollWrapper';
|
import {
|
||||||
|
ContextProviderName,
|
||||||
|
getContextByProviderName,
|
||||||
|
} from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||||
|
|
||||||
export const useScrollWrapperScopedRef = () => {
|
export const useScrollWrapperScopedRef = (
|
||||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
contextProviderName: ContextProviderName,
|
||||||
|
) => {
|
||||||
|
const Context = getContextByProviderName(contextProviderName);
|
||||||
|
const scrollWrapperRef = useContext(Context);
|
||||||
|
|
||||||
if (isUndefinedOrNull(scrollWrapperRef))
|
if (isUndefinedOrNull(scrollWrapperRef))
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||||
|
|
||||||
|
export const scrollLeftComponentState = createComponentState<number>({
|
||||||
|
key: 'scroll/scrollLeftComponentState',
|
||||||
|
defaultValue: 0,
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui';
|
|
||||||
|
|
||||||
export const scrollLeftState = createState<number>({
|
|
||||||
key: 'scroll/scrollLeftState',
|
|
||||||
defaultValue: 0,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||||
|
|
||||||
|
export const scrollTopComponentState = createComponentState<number>({
|
||||||
|
key: 'scroll/scrollTopComponentState',
|
||||||
|
defaultValue: 0,
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui';
|
|
||||||
|
|
||||||
export const scrollTopState = createState<number>({
|
|
||||||
key: 'scroll/scrollTopState',
|
|
||||||
defaultValue: 0,
|
|
||||||
});
|
|
||||||
@ -111,7 +111,7 @@ export const Releases = () => {
|
|||||||
<SubMenuTopBarContainer Icon={IconRocket} title="Releases">
|
<SubMenuTopBarContainer Icon={IconRocket} title="Releases">
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<StyledH1Title title="Releases" />
|
<StyledH1Title title="Releases" />
|
||||||
<ScrollWrapper>
|
<ScrollWrapper contextProviderName="releases">
|
||||||
<StyledReleaseContainer>
|
<StyledReleaseContainer>
|
||||||
{releases.map((release) => (
|
{releases.map((release) => (
|
||||||
<React.Fragment key={release.slug}>
|
<React.Fragment key={release.slug}>
|
||||||
|
|||||||
Reference in New Issue
Block a user