Feat: The scrollbar should fade away when the scroll is finished or not started (#1269)

* The scrollbar should fade away when the scroll is finished or not started

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>

* Complete scroll work

* Fix pr

* Fix pr

---------

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-twenty
2023-08-24 23:13:53 +00:00
committed by GitHub
parent 75207b093b
commit e373d17a2a
8 changed files with 87 additions and 18 deletions

View File

@ -14,6 +14,8 @@ import { BoardColumnIdContext } from '@/ui/board/contexts/BoardColumnIdContext';
import { SelectedSortType } from '@/ui/filter-n-sort/types/interface'; import { SelectedSortType } from '@/ui/filter-n-sort/types/interface';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { StyledScrollWrapper } from '@/ui/utilities/scroll/components/StyledScrollWrapper';
import { useListenScroll } from '@/ui/utilities/scroll/hooks/useListenScroll';
import { import {
PipelineProgress, PipelineProgress,
PipelineProgressOrderByWithRelationInput, PipelineProgressOrderByWithRelationInput,
@ -29,11 +31,8 @@ import { BoardOptions } from '../types/BoardOptions';
import { EntityBoardColumn } from './EntityBoardColumn'; import { EntityBoardColumn } from './EntityBoardColumn';
const StyledBoardWithHeader = styled.div` const StyledCustomScrollWrapper = styled(StyledScrollWrapper)`
display: flex;
flex: 1;
flex-direction: column; flex-direction: column;
width: 100%;
`; `;
export function EntityBoard({ export function EntityBoard({
@ -104,10 +103,15 @@ export function EntityBoard({
return a.index - b.index; return a.index - b.index;
}); });
const boardRef = useRef(null); const scrollableRef = useRef<HTMLDivElement>(null);
const boardRef = useRef<HTMLDivElement>(null);
useListenScroll({
scrollableRef,
});
return (boardColumns?.length ?? 0) > 0 ? ( return (boardColumns?.length ?? 0) > 0 ? (
<StyledBoardWithHeader> <StyledCustomScrollWrapper ref={scrollableRef}>
<BoardHeader <BoardHeader
viewName="All opportunities" viewName="All opportunities"
viewIcon={<IconList size={theme.icon.size.md} />} viewIcon={<IconList size={theme.icon.size.md} />}
@ -115,7 +119,7 @@ export function EntityBoard({
onSortsUpdate={updateSorts} onSortsUpdate={updateSorts}
context={CompanyBoardRecoilScopeContext} context={CompanyBoardRecoilScopeContext}
/> />
<StyledBoard ref={boardRef}> <StyledBoard>
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
{sortedBoardColumns.map((column) => ( {sortedBoardColumns.map((column) => (
<BoardColumnIdContext.Provider value={column.id} key={column.id}> <BoardColumnIdContext.Provider value={column.id} key={column.id}>
@ -137,7 +141,7 @@ export function EntityBoard({
dragSelectable={boardRef} dragSelectable={boardRef}
onDragSelectionChange={setCardSelected} onDragSelectionChange={setCardSelected}
/> />
</StyledBoardWithHeader> </StyledCustomScrollWrapper>
) : ( ) : (
<></> <></>
); );

View File

@ -30,7 +30,7 @@ const StyledLayout = styled.div`
} }
*::-webkit-scrollbar-thumb { *::-webkit-scrollbar-thumb {
background-color: ${({ theme }) => theme.border.color.medium}; background-color: transparent;
border-radius: ${({ theme }) => theme.border.radius.sm}; border-radius: ${({ theme }) => theme.border.radius.sm};
} }
`; `;

View File

@ -8,7 +8,6 @@ const StyledPanel = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
height: 100%; height: 100%;
overflow: auto;
width: 100%; width: 100%;
`; `;

View File

@ -8,6 +8,8 @@ import type {
import { SortType } from '@/ui/filter-n-sort/types/interface'; import { SortType } from '@/ui/filter-n-sort/types/interface';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { StyledScrollWrapper } from '@/ui/utilities/scroll/components/StyledScrollWrapper';
import { useListenScroll } from '@/ui/utilities/scroll/hooks/useListenScroll';
import { EntityUpdateMutationContext } from '../contexts/EntityUpdateMutationHookContext'; import { EntityUpdateMutationContext } from '../contexts/EntityUpdateMutationHookContext';
import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus'; import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
@ -87,11 +89,6 @@ const StyledTableContainer = styled.div`
overflow: auto; overflow: auto;
`; `;
const StyledTableWrapper = styled.div`
flex: 1;
overflow: auto;
`;
type OwnProps<SortField> = { type OwnProps<SortField> = {
viewName: string; viewName: string;
viewIcon?: React.ReactNode; viewIcon?: React.ReactNode;
@ -128,6 +125,12 @@ export function EntityTable<SortField>({
}, },
}); });
const scrollableRef = useRef<HTMLDivElement>(null);
useListenScroll({
scrollableRef,
});
return ( return (
<EntityUpdateMutationContext.Provider value={updateEntityMutation}> <EntityUpdateMutationContext.Provider value={updateEntityMutation}>
<StyledTableWithHeader> <StyledTableWithHeader>
@ -140,12 +143,12 @@ export function EntityTable<SortField>({
onViewSubmit={onViewSubmit} onViewSubmit={onViewSubmit}
onImport={onImport} onImport={onImport}
/> />
<StyledTableWrapper> <StyledScrollWrapper ref={scrollableRef}>
<StyledTable> <StyledTable>
<EntityTableHeader onColumnsChange={onColumnsChange} /> <EntityTableHeader onColumnsChange={onColumnsChange} />
<EntityTableBody /> <EntityTableBody />
</StyledTable> </StyledTable>
</StyledTableWrapper> </StyledScrollWrapper>
<DragSelect <DragSelect
dragSelectable={tableBodyRef} dragSelectable={tableBodyRef}
onDragSelectionStart={resetTableRowSelection} onDragSelectionStart={resetTableRowSelection}

View File

@ -0,0 +1,12 @@
import styled from '@emotion/styled';
export const StyledScrollWrapper = styled.div`
display: flex;
height: 100%;
overflow: auto;
width: 100%;
&.scrolling::-webkit-scrollbar-thumb {
background-color: ${({ theme }) => theme.border.color.medium};
}
`;

View File

@ -0,0 +1,45 @@
import { useEffect } from 'react';
import debounce from 'lodash.debounce';
import { useRecoilCallback } from 'recoil';
import { isScrollingState } from '../states/isScrollingState';
export function useListenScroll<T extends Element>({
scrollableRef,
}: {
scrollableRef: React.RefObject<T>;
}) {
const hideScrollBarsCallback = useRecoilCallback(({ snapshot }) => () => {
const isScrolling = snapshot.getLoadable(isScrollingState).getValue();
if (!isScrolling) {
scrollableRef.current?.classList.remove('scrolling');
}
});
const handleScrollStart = useRecoilCallback(({ set }) => () => {
set(isScrollingState, true);
scrollableRef.current?.classList.add('scrolling');
});
const handleScrollEnd = useRecoilCallback(({ set }) => () => {
set(isScrollingState, false);
debounce(hideScrollBarsCallback, 1000)();
});
useEffect(() => {
const refTarget = scrollableRef.current;
refTarget?.addEventListener('scrollend', handleScrollEnd);
refTarget?.addEventListener('scroll', handleScrollStart);
return () => {
refTarget?.removeEventListener('scrollend', handleScrollEnd);
refTarget?.removeEventListener('scroll', handleScrollStart);
};
}, [
hideScrollBarsCallback,
handleScrollStart,
handleScrollEnd,
scrollableRef,
]);
}

View File

@ -0,0 +1,6 @@
import { atom } from 'recoil';
export const isScrollingState = atom({
key: 'scroll/isScollingState',
default: false,
});

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { getOperationName } from '@apollo/client/utilities'; import { getOperationName } from '@apollo/client/utilities';
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
@ -49,6 +48,7 @@ export function Companies() {
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
accountOwner: null, accountOwner: null,
linkedinUrl: '', linkedinUrl: '',
idealCustomerProfile: false,
employees: null, employees: null,
idealCustomerProfile: false, idealCustomerProfile: false,
}, },