Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 98 additions & 24 deletions apps/cowswap-frontend/src/common/pure/VirtualList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, useCallback, useRef } from 'react'
import { ReactNode, useCallback, useLayoutEffect, useRef } from 'react'

import { useVirtualizer, VirtualItem } from '@tanstack/react-virtual'
import ms from 'ms.macro'
Expand All @@ -7,15 +7,72 @@ import { ListInner, ListScroller, ListWrapper, LoadingRows } from './styled'

const scrollDelay = ms`400ms`

// TODO: Add proper return type annotation
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const threeDivs = () => (
<>
<div />
<div />
<div />
</>
)
const LoadingPlaceholder: () => ReactNode = () => {
return (
<>
<div />
<div />
<div />
</>
)
}

interface VirtualListRowProps<T> {
item: VirtualItem
loading?: boolean
items: T[]
getItemView(items: T[], item: VirtualItem): ReactNode
measureElement(element: Element | null): void
}

function VirtualListRow<T>({ item, loading, items, getItemView, measureElement }: VirtualListRowProps<T>): ReactNode {
if (loading) {
return (
<LoadingRows>
<LoadingPlaceholder />
</LoadingRows>
)
}

return (
<div data-index={item.index} ref={measureElement}>
{getItemView(items, item)}
</div>
)
}

interface VirtualListRowsProps<T> {
virtualItems: VirtualItem[]
loading?: boolean
items: T[]
getItemView(items: T[], item: VirtualItem): ReactNode
measureElement(element: Element | null): void
}

function renderVirtualListRows<T>({
virtualItems,
loading,
items,
getItemView,
measureElement,
}: VirtualListRowsProps<T>): ReactNode[] {
const elements: ReactNode[] = []

for (const item of virtualItems) {
elements.push(
<VirtualListRow
key={item.key}
item={item}
loading={loading}
items={items}
getItemView={getItemView}
measureElement={measureElement}
/>,
)
}

return elements
}

interface VirtualListProps<T> {
id?: string
Expand All @@ -26,18 +83,18 @@ interface VirtualListProps<T> {
loading?: boolean
estimateSize?: () => number
children?: ReactNode
scrollResetKey?: string | number | boolean
}

// TODO: Add proper return type annotation
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function VirtualList<T>({
id,
items,
loading,
getItemView,
children,
estimateSize = () => 56,
}: VirtualListProps<T>) {
scrollResetKey,
}: VirtualListProps<T>): ReactNode {
const parentRef = useRef<HTMLDivElement>(null)
const wrapperRef = useRef<HTMLDivElement>(null)
const scrollTimeoutRef = useRef<NodeJS.Timeout>(undefined)
Expand All @@ -53,31 +110,48 @@ export function VirtualList<T>({
}, scrollDelay)
}, [])

// eslint-disable-next-line react-hooks/incompatible-library
const virtualizer = useVirtualizer({
getScrollElement: () => parentRef.current,
count: items.length,
estimateSize,
overscan: 5,
})

useLayoutEffect(() => {
if (scrollResetKey === undefined) {
return
}

const scrollContainer = parentRef.current

if (scrollContainer) {
scrollContainer.scrollTop = 0
scrollContainer.scrollLeft = 0

if (typeof scrollContainer.scrollTo === 'function') {
scrollContainer.scrollTo({ top: 0, left: 0, behavior: 'auto' })
}
}

virtualizer.scrollToOffset(0, { align: 'start' })
}, [scrollResetKey, virtualizer])

const virtualItems = virtualizer.getVirtualItems()
const virtualRows = renderVirtualListRows({
virtualItems,
loading,
items,
getItemView,
measureElement: virtualizer.measureElement,
})

return (
<ListWrapper id={id} ref={parentRef} onScroll={onScroll}>
<ListInner ref={wrapperRef} style={{ height: virtualizer.getTotalSize() }}>
<ListScroller style={{ transform: `translateY(${virtualItems[0]?.start ?? 0}px)` }}>
{children}
{virtualItems.map((item) => {
if (loading) {
return <LoadingRows key={item.key}>{threeDivs()}</LoadingRows>
}

return (
<div key={item.key} data-index={item.index} ref={virtualizer.measureElement}>
{getItemView(items, item)}
</div>
)
})}
{virtualRows}
</ListScroller>
</ListInner>
</ListWrapper>
Expand Down
27 changes: 14 additions & 13 deletions apps/cowswap-frontend/src/locales/en-US.po
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,6 @@ msgid "View details"
msgstr "View details"

#: apps/cowswap-frontend/src/modules/application/containers/App/menuConsts.tsx
#: apps/cowswap-frontend/src/modules/tokensList/pure/ChainsSelector/index.tsx
msgid "More"
msgstr "More"

Expand Down Expand Up @@ -827,8 +826,8 @@ msgid "Copied"
msgstr "Copied"

#: apps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsx
msgid "Can't find your token on the list?"
msgstr "Can't find your token on the list?"
#~ msgid "Can't find your token on the list?"
#~ msgstr "Can't find your token on the list?"

#: apps/cowswap-frontend/src/modules/trade/pure/ReceiveAmountTitle/index.tsx
msgid "icon"
Expand All @@ -847,8 +846,8 @@ msgid "Please connect your wallet to one of our supported networks."
msgstr "Please connect your wallet to one of our supported networks."

#: apps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsx
msgid "<0>Read our guide</0> on how to add custom tokens."
msgstr "<0>Read our guide</0> on how to add custom tokens."
#~ msgid "<0>Read our guide</0> on how to add custom tokens."
#~ msgstr "<0>Read our guide</0> on how to add custom tokens."

#: apps/cowswap-frontend/src/modules/hooksStore/containers/TenderlySimulate/index.tsx
msgid "Retry"
Expand Down Expand Up @@ -1220,8 +1219,8 @@ msgid "Partner fee can not be more than {PARTNER_FEE_MAX_BPS} BPS!"
msgstr "Partner fee can not be more than {PARTNER_FEE_MAX_BPS} BPS!"

#: apps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsx
msgid "Manage Token Lists"
msgstr "Manage Token Lists"
#~ msgid "Manage Token Lists"
#~ msgstr "Manage Token Lists"

#: apps/cowswap-frontend/src/legacy/components/Tokens/TokensTable.tsx
msgid "No results found"
Expand Down Expand Up @@ -3156,7 +3155,6 @@ msgstr "CoW Swap's robust solver competition protects your slippage from being e
msgid "Aave Debt Swap Flashloan"
msgstr "Aave Debt Swap Flashloan"

#: apps/cowswap-frontend/src/modules/tokensList/pure/LpTokenLists/index.tsx
#: apps/cowswap-frontend/src/modules/yield/pure/TargetPoolPreviewInfo.tsx
msgid "Details"
msgstr "Details"
Expand Down Expand Up @@ -3812,6 +3810,10 @@ msgstr "User rejected approval transaction"
msgid "Swap on"
msgstr "Swap on"

#: apps/cowswap-frontend/src/modules/tokensList/pure/TokenSearchContent/index.tsx
msgid "Can't find your token on the list? <0>Read our guide</0> on how to add custom tokens."
msgstr "Can't find your token on the list? <0>Read our guide</0> on how to add custom tokens."

#: apps/cowswap-frontend/src/modules/account/containers/Transaction/ActivityDetails.tsx
#: apps/cowswap-frontend/src/modules/orderProgressBar/pure/TransactionSubmittedContent/index.tsx
msgid "Transaction"
Expand Down Expand Up @@ -4322,7 +4324,6 @@ msgstr "Decrease Value"
#: apps/cowswap-frontend/src/legacy/components/Tokens/TokensTable.tsx
#: apps/cowswap-frontend/src/modules/ethFlow/pure/WrappingPreview/WrapCard.tsx
#: apps/cowswap-frontend/src/modules/tokensList/pure/LpTokenLists/index.tsx
#: apps/cowswap-frontend/src/modules/tokensList/pure/LpTokenLists/index.tsx
msgid "Balance"
msgstr "Balance"

Expand Down Expand Up @@ -4385,8 +4386,8 @@ msgid "funds"
msgstr "funds"

#: apps/cowswap-frontend/src/modules/tokensList/pure/LpTokenLists/index.tsx
msgid "Pool details"
msgstr "Pool details"
#~ msgid "Pool details"
#~ msgstr "Pool details"

#: apps/cowswap-frontend/src/modules/tradeSlippage/containers/HighSuggestedSlippageWarning/index.tsx
msgid "Slippage adjusted to {slippageBpsPercentage}% to ensure quick execution"
Expand Down Expand Up @@ -5894,8 +5895,8 @@ msgid "You sold <0/>"
msgstr "You sold <0/>"

#: apps/cowswap-frontend/src/modules/tokensList/pure/ChainsSelector/index.tsx
msgid "Less"
msgstr "Less"
#~ msgid "Less"
#~ msgstr "Less"

#: libs/hook-dapp-lib/src/hookDappsRegistry.ts
msgid "Claim your LlamaPay vesting contract funds"
Expand Down
1 change: 1 addition & 0 deletions apps/cowswap-frontend/src/theme/consts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const WIDGET_MAX_WIDTH = {
limit: '1350px',
content: '680px',
tokenSelect: '590px',
tokenSelectSidebar: '700px',
}

export const TextWrapper = styled(Text)<{ color: keyof Colors; override?: boolean }>`
Expand Down
Loading