mirror of
https://github.com/twentyhq/twenty.git
synced 2025-01-04 10:16:37 +03:00
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:
parent
0a7700351f
commit
1030ff43d8
@ -46,7 +46,7 @@ export const EventList = ({ events, targetableObject }: EventListProps) => {
|
||||
const groupedEvents = groupEventsByMonth(filteredEvents);
|
||||
|
||||
return (
|
||||
<ScrollWrapper>
|
||||
<ScrollWrapper contextProviderName="eventList">
|
||||
<StyledTimelineContainer>
|
||||
{groupedEvents.map((group, index) => (
|
||||
<EventsGroup
|
||||
|
@ -349,7 +349,7 @@ export const CommandMenu = () => {
|
||||
)}
|
||||
</StyledInputContainer>
|
||||
<StyledList>
|
||||
<ScrollWrapper>
|
||||
<ScrollWrapper contextProviderName="commandMenu">
|
||||
<StyledInnerList isMobile={isMobile}>
|
||||
<SelectableList
|
||||
selectableListId="command-menu-list"
|
||||
|
@ -148,7 +148,7 @@ export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => {
|
||||
>
|
||||
<StyledWrapper>
|
||||
<StyledBoardHeader />
|
||||
<ScrollWrapper>
|
||||
<ScrollWrapper contextProviderName="recordBoard">
|
||||
<StyledContainer ref={boardRef}>
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
{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 { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||
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 }>`
|
||||
background-color: ${({ theme, selected }) =>
|
||||
@ -199,10 +199,10 @@ export const RecordBoardCard = () => {
|
||||
return [updateEntity, { loading: false }];
|
||||
};
|
||||
|
||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
||||
const scrollWrapperRef = useContext(RecordBoardScrollWrapperContext);
|
||||
|
||||
const { ref: cardRef, inView } = useInView({
|
||||
root: scrollWrapperRef.current,
|
||||
root: scrollWrapperRef?.ref.current,
|
||||
rootMargin: '1000px',
|
||||
});
|
||||
|
||||
|
@ -70,7 +70,7 @@ export const RecordTableWithWrappers = ({
|
||||
|
||||
return (
|
||||
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
||||
<ScrollWrapper>
|
||||
<ScrollWrapper contextProviderName="recordTableWithWrappers">
|
||||
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
||||
<StyledTableWithHeader>
|
||||
<StyledTableContainer>
|
||||
|
@ -10,8 +10,8 @@ import { useRecordTableStates } from '@/object-record/record-table/hooks/interna
|
||||
import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState';
|
||||
import { isRecordTableScrolledTopComponentState } from '@/object-record/record-table/states/isRecordTableScrolledTopComponentState';
|
||||
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
||||
import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState';
|
||||
import { scrollTopState } from '@/ui/utilities/scroll/states/scrollTopState';
|
||||
import { useScrollLeftValue } from '@/ui/utilities/scroll/hooks/useScrollLeftValue';
|
||||
import { useScrollTopValue } from '@/ui/utilities/scroll/hooks/useScrollTopValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
||||
@ -38,7 +38,7 @@ export const RecordTableBodyEffect = () => {
|
||||
|
||||
const tableLastRowVisible = useRecoilValue(tableLastRowVisibleState);
|
||||
|
||||
const scrollTop = useRecoilValue(scrollTopState);
|
||||
const scrollTop = useScrollTopValue('recordTableWithWrappers');
|
||||
const setIsRecordTableScrolledTop = useSetRecoilComponentState(
|
||||
isRecordTableScrolledTopComponentState,
|
||||
);
|
||||
@ -57,7 +57,7 @@ export const RecordTableBodyEffect = () => {
|
||||
}
|
||||
}, [scrollTop, setIsRecordTableScrolledTop]);
|
||||
|
||||
const scrollLeft = useRecoilValue(scrollLeftState);
|
||||
const scrollLeft = useScrollLeftValue('recordTableWithWrappers');
|
||||
|
||||
const setIsRecordTableScrolledLeft = useSetRecoilComponentState(
|
||||
isRecordTableScrolledLeftComponentState,
|
||||
|
@ -1,13 +1,13 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { GRAY_SCALE } from 'twenty-ui';
|
||||
|
||||
import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
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 = {
|
||||
objectNameSingular: string;
|
||||
@ -40,12 +40,14 @@ export const RecordTableBodyFetchMoreLoader = ({
|
||||
[setRecordTableLastRowVisible],
|
||||
);
|
||||
|
||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
||||
const scrollWrapperRef = useContext(
|
||||
RecordTableWithWrappersScrollWrapperContext,
|
||||
);
|
||||
|
||||
const { ref: tbodyRef } = useInView({
|
||||
onChange: onLastRowVisible,
|
||||
rootMargin: '1000px',
|
||||
root: scrollWrapperRef.current?.querySelector(
|
||||
root: scrollWrapperRef?.ref.current?.querySelector(
|
||||
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
|
||||
),
|
||||
});
|
||||
|
@ -54,11 +54,11 @@ const HIDDEN_TABLE_COLUMN_DROPDOWN_HOTKEY_SCOPE_ID =
|
||||
export const RecordTableHeaderLastColumn = () => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
const scrollWrapper = useScrollWrapperScopedRef();
|
||||
const scrollWrapper = useScrollWrapperScopedRef('recordTableWithWrappers');
|
||||
|
||||
const isTableWiderThanScreen =
|
||||
(scrollWrapper.current?.clientWidth ?? 0) <
|
||||
(scrollWrapper.current?.scrollWidth ?? 0);
|
||||
(scrollWrapper.ref.current?.clientWidth ?? 0) <
|
||||
(scrollWrapper.ref.current?.scrollWidth ?? 0);
|
||||
|
||||
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 { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||
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 = ({
|
||||
recordId,
|
||||
@ -31,10 +31,12 @@ export const RecordTableRowWrapper = ({
|
||||
const { isRowSelectedFamilyState } = useRecordTableStates();
|
||||
const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId));
|
||||
|
||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
||||
const scrollWrapperRef = useContext(
|
||||
RecordTableWithWrappersScrollWrapperContext,
|
||||
);
|
||||
|
||||
const { ref: elementRef, inView } = useInView({
|
||||
root: scrollWrapperRef.current?.querySelector(
|
||||
root: scrollWrapperRef.ref.current?.querySelector(
|
||||
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
|
||||
),
|
||||
rootMargin: '1000px',
|
||||
|
@ -34,7 +34,7 @@ export const SettingsPageContainer = ({
|
||||
}: {
|
||||
children: ReactNode;
|
||||
}) => (
|
||||
<StyledScrollWrapper>
|
||||
<StyledScrollWrapper contextProviderName="settingsPageContainer">
|
||||
<StyledSettingsPageContainer>{children}</StyledSettingsPageContainer>
|
||||
</StyledScrollWrapper>
|
||||
);
|
||||
|
@ -45,7 +45,7 @@ export const DropdownMenuItemsContainer = ({
|
||||
return (
|
||||
<StyledDropdownMenuItemsExternalContainer hasMaxHeight={hasMaxHeight}>
|
||||
{hasMaxHeight ? (
|
||||
<StyledScrollWrapper>
|
||||
<StyledScrollWrapper contextProviderName="dropdownMenuItemsContainer">
|
||||
<StyledDropdownMenuItemsInternalContainer>
|
||||
{children}
|
||||
</StyledDropdownMenuItemsInternalContainer>
|
||||
|
@ -32,7 +32,7 @@ export const ShowPageContainer = ({ children }: ShowPageContainerProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
return isMobile ? (
|
||||
<StyledOuterContainer>
|
||||
<StyledScrollWrapper>
|
||||
<StyledScrollWrapper contextProviderName="showPageContainer">
|
||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||
</StyledScrollWrapper>
|
||||
</StyledOuterContainer>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ReactNode } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
@ -46,7 +46,7 @@ export const ShowPageLeftContainer = ({
|
||||
{children}
|
||||
</StyledInnerContainer>
|
||||
) : (
|
||||
<ScrollWrapper>
|
||||
<ScrollWrapper contextProviderName="showPageLeftContainer">
|
||||
<StyledIntermediateContainer>
|
||||
<StyledInnerContainer isMobile={isMobile}>
|
||||
{children}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import * as React from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
|
||||
@ -53,7 +53,7 @@ export const TabList = ({
|
||||
|
||||
return (
|
||||
<TabListScope tabListScopeId={tabListId}>
|
||||
<ScrollWrapper hideY>
|
||||
<ScrollWrapper hideY contextProviderName="tabList">
|
||||
<StyledContainer className={className}>
|
||||
{tabs
|
||||
.filter((tab) => !tab.hide)
|
||||
|
@ -1,19 +1,18 @@
|
||||
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 { 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 { 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%;
|
||||
@ -29,6 +28,7 @@ export type ScrollWrapperProps = {
|
||||
className?: string;
|
||||
hideY?: boolean;
|
||||
hideX?: boolean;
|
||||
contextProviderName: ContextProviderName;
|
||||
};
|
||||
|
||||
export const ScrollWrapper = ({
|
||||
@ -36,18 +36,21 @@ export const ScrollWrapper = ({
|
||||
className,
|
||||
hideX,
|
||||
hideY,
|
||||
contextProviderName,
|
||||
}: ScrollWrapperProps) => {
|
||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||
const Context = getContextByProviderName(contextProviderName);
|
||||
|
||||
const handleScroll = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(overlayScroll: OverlayScrollbars) => {
|
||||
const target = overlayScroll.elements().scrollOffsetElement;
|
||||
set(scrollTopState, target.scrollTop);
|
||||
set(scrollLeftState, target.scrollLeft);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const { scrollTopComponentState, scrollLeftComponentState } =
|
||||
useScrollStates(contextProviderName);
|
||||
const setScrollTop = useSetRecoilState(scrollTopComponentState);
|
||||
const setScrollLeft = useSetRecoilState(scrollLeftComponentState);
|
||||
|
||||
const handleScroll = (overlayScroll: OverlayScrollbars) => {
|
||||
const target = overlayScroll.elements().scrollOffsetElement;
|
||||
setScrollTop(target.scrollTop);
|
||||
setScrollLeft(target.scrollLeft);
|
||||
};
|
||||
|
||||
const setOverlayScrollbars = useSetRecoilState(overlayScrollbarsState);
|
||||
|
||||
@ -75,10 +78,10 @@ export const ScrollWrapper = ({
|
||||
}, [instance, setOverlayScrollbars]);
|
||||
|
||||
return (
|
||||
<ScrollWrapperContext.Provider value={scrollableRef}>
|
||||
<Context.Provider value={{ ref: scrollableRef, id: contextProviderName }}>
|
||||
<StyledScrollWrapper ref={scrollableRef} className={className}>
|
||||
{children}
|
||||
</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', () => {
|
||||
it('should return the scrollWrapperRef if available', () => {
|
||||
const { result } = renderHook(() => useScrollWrapperScopedRef());
|
||||
const { result } = renderHook(() => useScrollWrapperScopedRef('test'));
|
||||
|
||||
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 { ScrollWrapperContext } from '../components/ScrollWrapper';
|
||||
import {
|
||||
ContextProviderName,
|
||||
getContextByProviderName,
|
||||
} from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||
|
||||
export const useScrollWrapperScopedRef = () => {
|
||||
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
||||
export const useScrollWrapperScopedRef = (
|
||||
contextProviderName: ContextProviderName,
|
||||
) => {
|
||||
const Context = getContextByProviderName(contextProviderName);
|
||||
const scrollWrapperRef = useContext(Context);
|
||||
|
||||
if (isUndefinedOrNull(scrollWrapperRef))
|
||||
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">
|
||||
<SettingsPageContainer>
|
||||
<StyledH1Title title="Releases" />
|
||||
<ScrollWrapper>
|
||||
<ScrollWrapper contextProviderName="releases">
|
||||
<StyledReleaseContainer>
|
||||
{releases.map((release) => (
|
||||
<React.Fragment key={release.slug}>
|
||||
|
Loading…
Reference in New Issue
Block a user