feat: Trending Collections Table (#4694)
* Migrate Trending Collections: first pass * Adding types for react-table * Forgot to add yarn.lock * Update sprinkles colors and add accentSuccess to match Figma * Style cleanup * Fix overlap on activity items and text wrapping on Value Prop * Update header to new typography name * Make entire table row link to collection * Remove duplicated navigate() on table row * Use borderStyle: none (sprinkle) instead of hidden * Use common typography style for table header row * Sprinkles for rank styles * Sprinkles for TrendingOptions border styles * Update color on trendingOption active state * Restore useEffect to hide certain columns on mobile * forgot to save one file * Update accent color * Use isMobile instead of breakpoint check
This commit is contained in:
parent
1aa4afad5f
commit
f735c34841
@ -80,6 +80,7 @@
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-redux": "^7.1.24",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-table": "^7.7.12",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.0",
|
||||
"@types/react-window": "^1.8.2",
|
||||
"@types/rebass": "^4.0.7",
|
||||
|
@ -53,14 +53,7 @@ const ActivityFeed = ({ address }: { address: string }) => {
|
||||
</Column>
|
||||
<Column width="full" position="relative">
|
||||
{collectionActivity.events.map((activityEvent: ActivityEvent, index: number) => {
|
||||
return (
|
||||
<ActivityRow
|
||||
event={activityEvent}
|
||||
index={index}
|
||||
key={`${activityEvent.eventType}${activityEvent.tokenId}`}
|
||||
current={current}
|
||||
/>
|
||||
)
|
||||
return <ActivityRow event={activityEvent} index={index} key={index} current={current} />
|
||||
})}
|
||||
</Column>
|
||||
</Box>
|
||||
|
46
src/nft/components/explore/Cells/Cells.css.ts
Normal file
46
src/nft/components/explore/Cells/Cells.css.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { body } from '../../../css/common.css'
|
||||
import { sprinkles } from '../../../css/sprinkles.css'
|
||||
|
||||
export const logo = sprinkles({ borderRadius: '12' })
|
||||
|
||||
export const title = style([
|
||||
body,
|
||||
sprinkles({
|
||||
color: 'textPrimary',
|
||||
textAlign: 'left',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
paddingLeft: '12',
|
||||
paddingRight: '2',
|
||||
}),
|
||||
])
|
||||
|
||||
export const openAddress = sprinkles({
|
||||
minWidth: '20',
|
||||
height: '20',
|
||||
width: '20',
|
||||
})
|
||||
|
||||
export const address = style([
|
||||
title,
|
||||
sprinkles({
|
||||
marginLeft: '8',
|
||||
alignItems: 'center',
|
||||
minWidth: '0',
|
||||
width: 'max',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
}),
|
||||
])
|
||||
|
||||
export const verifiedBadge = sprinkles({
|
||||
display: 'inline-block',
|
||||
paddingTop: '4',
|
||||
height: '28',
|
||||
width: '28',
|
||||
textAlign: 'left',
|
||||
})
|
102
src/nft/components/explore/Cells/Cells.tsx
Normal file
102
src/nft/components/explore/Cells/Cells.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
import { ethNumberStandardFormatter, formatWeiToDecimal } from '../../../utils/currency'
|
||||
import { putCommas } from '../../../utils/putCommas'
|
||||
import { formatChange } from '../../../utils/toSignificant'
|
||||
import { Box } from '../../Box'
|
||||
import { Column, Row } from '../../Flex'
|
||||
import { VerifiedIcon } from '../../icons'
|
||||
import * as styles from './Cells.css'
|
||||
|
||||
interface CellProps {
|
||||
value: {
|
||||
logo?: string
|
||||
name?: string
|
||||
address?: string
|
||||
isVerified?: boolean
|
||||
value?: number
|
||||
change?: number
|
||||
}
|
||||
}
|
||||
|
||||
export const CollectionTitleCell = ({ value }: CellProps) => {
|
||||
return (
|
||||
<Row as="span" style={{ marginLeft: '52px' }}>
|
||||
<img className={styles.logo} src={value.logo} alt={`${value.name} logo`} height={44} width={44} />
|
||||
<span className={styles.title}>{value.name}</span>
|
||||
{value.isVerified && (
|
||||
<span className={styles.verifiedBadge}>
|
||||
<VerifiedIcon />
|
||||
</span>
|
||||
)}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
export const WithCommaCell = ({ value }: CellProps) => <span>{value.value ? putCommas(value.value) : '-'}</span>
|
||||
|
||||
export const EthCell = ({ value }: { value: number }) => (
|
||||
<Row justifyContent="flex-end" color="textPrimary">
|
||||
{value ? <>{formatWeiToDecimal(value.toString())} ETH</> : '-'}
|
||||
</Row>
|
||||
)
|
||||
|
||||
export const VolumeCell = ({ value }: CellProps) => (
|
||||
<Row justifyContent="flex-end" color="textPrimary">
|
||||
{value.value ? <>{ethNumberStandardFormatter(value.value.toString())} ETH</> : '-'}
|
||||
</Row>
|
||||
)
|
||||
|
||||
export const EthWithDayChange = ({ value }: CellProps) => (
|
||||
<Column gap="4">
|
||||
<VolumeCell value={{ value: value.value }} />
|
||||
{value.change ? (
|
||||
<Box
|
||||
as="span"
|
||||
color={value.change > 0 ? 'green' : 'accentFailure'}
|
||||
fontWeight="normal"
|
||||
fontSize="12"
|
||||
position="relative"
|
||||
>
|
||||
{value.change > 0 && '+'}
|
||||
{formatChange(value.change)}%
|
||||
</Box>
|
||||
) : null}
|
||||
</Column>
|
||||
)
|
||||
|
||||
export const WeiWithDayChange = ({ value }: CellProps) => (
|
||||
<Column gap="4">
|
||||
<Row justifyContent="flex-end" color="textPrimary">
|
||||
{value && value.value ? <>{formatWeiToDecimal(value.value.toString())} ETH</> : '-'}
|
||||
</Row>
|
||||
{value.change ? (
|
||||
<Box
|
||||
as="span"
|
||||
color={value.change > 0 ? 'green' : 'accentFailure'}
|
||||
fontWeight="normal"
|
||||
fontSize="12"
|
||||
position="relative"
|
||||
>
|
||||
{value.change > 0 && '+'}
|
||||
{formatChange(value.change)}%
|
||||
</Box>
|
||||
) : null}
|
||||
</Column>
|
||||
)
|
||||
|
||||
export const CommaWithDayChange = ({ value }: CellProps) => (
|
||||
<Column gap="4">
|
||||
<WithCommaCell value={value} />
|
||||
{value.change ? (
|
||||
<Box
|
||||
as="span"
|
||||
color={value.change > 0 ? 'green' : 'accentFailure'}
|
||||
fontWeight="normal"
|
||||
fontSize="12"
|
||||
position="relative"
|
||||
>
|
||||
{value.change > 0 && '+'}
|
||||
{formatChange(value.change)}%
|
||||
</Box>
|
||||
) : null}
|
||||
</Column>
|
||||
)
|
84
src/nft/components/explore/CollectionTable.tsx
Normal file
84
src/nft/components/explore/CollectionTable.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import { CellProps, Column } from 'react-table'
|
||||
|
||||
import { CollectionTableColumn } from '../../types'
|
||||
import {
|
||||
CollectionTitleCell,
|
||||
CommaWithDayChange,
|
||||
EthWithDayChange,
|
||||
WeiWithDayChange,
|
||||
WithCommaCell,
|
||||
} from './Cells/Cells'
|
||||
import { Table } from './Table'
|
||||
|
||||
export enum ColumnHeaders {
|
||||
Volume = 'Volume',
|
||||
Floor = 'Floor',
|
||||
Sales = 'Sales',
|
||||
Items = 'Items',
|
||||
Owners = 'Owners',
|
||||
}
|
||||
|
||||
const columns: Column<CollectionTableColumn>[] = [
|
||||
{
|
||||
Header: 'Collection',
|
||||
accessor: 'collection',
|
||||
Cell: CollectionTitleCell,
|
||||
},
|
||||
{
|
||||
id: ColumnHeaders.Volume,
|
||||
Header: ColumnHeaders.Volume,
|
||||
accessor: ({ volume }) => volume.value,
|
||||
sortDescFirst: true,
|
||||
Cell: function EthDayChanget(cell: CellProps<CollectionTableColumn>) {
|
||||
return <EthWithDayChange value={cell.row.original.volume} />
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ColumnHeaders.Floor,
|
||||
Header: ColumnHeaders.Floor,
|
||||
accessor: ({ floor }) => floor.value,
|
||||
sortDescFirst: true,
|
||||
Cell: function weiDayChange(cell: CellProps<CollectionTableColumn>) {
|
||||
return <WeiWithDayChange value={cell.row.original.floor} />
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ColumnHeaders.Sales,
|
||||
Header: ColumnHeaders.Sales,
|
||||
accessor: 'sales',
|
||||
sortDescFirst: true,
|
||||
Cell: function withCommaCell(cell: CellProps<CollectionTableColumn>) {
|
||||
return <WithCommaCell value={{ value: cell.row.original.sales }} />
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ColumnHeaders.Items,
|
||||
Header: ColumnHeaders.Items,
|
||||
accessor: 'totalSupply',
|
||||
sortDescFirst: true,
|
||||
Cell: function withCommaCell(cell: CellProps<CollectionTableColumn>) {
|
||||
return <WithCommaCell value={{ value: cell.row.original.totalSupply }} />
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: ColumnHeaders.Owners,
|
||||
accessor: ({ owners }) => owners.value,
|
||||
sortDescFirst: true,
|
||||
Cell: function commaDayChange(cell: CellProps<CollectionTableColumn>) {
|
||||
return <CommaWithDayChange value={cell.row.original.owners} />
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const CollectionTable = ({ data }: { data: CollectionTableColumn[] }) => {
|
||||
return (
|
||||
<>
|
||||
<Table
|
||||
hiddenColumns={[ColumnHeaders.Volume, ColumnHeaders.Owners, ColumnHeaders.Items, ColumnHeaders.Sales]}
|
||||
{...{ data, columns }}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CollectionTable
|
@ -1,4 +1,5 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
import { body, caption } from 'nft/css/common.css'
|
||||
import { breakpoints, sprinkles } from 'nft/css/sprinkles.css'
|
||||
|
||||
export const section = style([
|
||||
@ -30,11 +31,11 @@ export const bannerWrap = style([
|
||||
|
||||
export const bannerOverlay = style([
|
||||
{
|
||||
opacity: '0.7',
|
||||
height: '386px',
|
||||
},
|
||||
sprinkles({
|
||||
position: 'absolute',
|
||||
opacity: '0.7',
|
||||
width: 'full',
|
||||
backgroundColor: 'grey900',
|
||||
left: '0',
|
||||
@ -204,7 +205,102 @@ export const valuePropContent = style([
|
||||
width: '58%',
|
||||
lineHeight: '36px',
|
||||
},
|
||||
[`(min-width: ${breakpoints.lg}px)`]: { width: '50%' },
|
||||
[`(min-width: ${breakpoints.lg - 1}px)`]: { width: '50%' },
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
/* Base Table Styles */
|
||||
|
||||
export const table = style([
|
||||
{
|
||||
borderCollapse: 'collapse',
|
||||
boxShadow: '0 0 0 1px rgba(153, 161, 189, 0.24)',
|
||||
borderSpacing: '0px 40px',
|
||||
},
|
||||
sprinkles({
|
||||
width: 'full',
|
||||
borderRadius: '12',
|
||||
borderStyle: 'none',
|
||||
}),
|
||||
])
|
||||
|
||||
export const thead = sprinkles({
|
||||
marginRight: '12',
|
||||
borderColor: 'outline',
|
||||
borderWidth: '1px',
|
||||
borderBottomStyle: 'solid',
|
||||
})
|
||||
|
||||
export const th = style([
|
||||
caption,
|
||||
{
|
||||
selectors: {
|
||||
'&:nth-last-child(1)': {
|
||||
paddingRight: '20px',
|
||||
},
|
||||
},
|
||||
},
|
||||
sprinkles({
|
||||
color: { default: 'textSecondary', hover: 'textPrimary' },
|
||||
cursor: 'pointer',
|
||||
paddingTop: '12',
|
||||
paddingBottom: '12',
|
||||
}),
|
||||
])
|
||||
|
||||
export const tr = sprinkles({ cursor: 'pointer' })
|
||||
|
||||
export const rank = sprinkles({
|
||||
color: 'textSecondary',
|
||||
position: 'absolute',
|
||||
display: { md: 'inline-block', sm: 'none' },
|
||||
left: '24',
|
||||
top: '20',
|
||||
})
|
||||
|
||||
export const td = style([
|
||||
body,
|
||||
{
|
||||
verticalAlign: 'middle',
|
||||
selectors: {
|
||||
'&:nth-last-child(1)': {
|
||||
paddingRight: '20px',
|
||||
},
|
||||
},
|
||||
},
|
||||
sprinkles({
|
||||
maxWidth: '160',
|
||||
paddingTop: '10',
|
||||
paddingBottom: '10',
|
||||
textAlign: 'right',
|
||||
position: 'relative',
|
||||
}),
|
||||
])
|
||||
|
||||
export const trendingOptions = sprinkles({
|
||||
marginBottom: '32',
|
||||
height: '44',
|
||||
borderRadius: '12',
|
||||
borderWidth: '2px',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'outline',
|
||||
})
|
||||
|
||||
/* Trending Colletion styles */
|
||||
export const trendingOption = style([
|
||||
{
|
||||
marginTop: '-1px',
|
||||
marginLeft: '-1px',
|
||||
},
|
||||
sprinkles({
|
||||
paddingY: '14',
|
||||
paddingX: '16',
|
||||
borderRadius: '12',
|
||||
fontSize: '12',
|
||||
display: 'inline-block',
|
||||
cursor: 'pointer',
|
||||
}),
|
||||
])
|
||||
|
||||
export const trendingOptionActive = sprinkles({ backgroundColor: 'accentActiveSoft' })
|
||||
|
117
src/nft/components/explore/Table.tsx
Normal file
117
src/nft/components/explore/Table.tsx
Normal file
@ -0,0 +1,117 @@
|
||||
import clsx from 'clsx'
|
||||
import { useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Column, IdType, useSortBy, useTable } from 'react-table'
|
||||
import { isMobile } from 'utils/userAgent'
|
||||
|
||||
import { Box } from '../../components/Box'
|
||||
import { CollectionTableColumn } from '../../types'
|
||||
import { ArrowRightIcon } from '../icons'
|
||||
import { ColumnHeaders } from './CollectionTable'
|
||||
import * as styles from './Explore.css'
|
||||
|
||||
interface TableProps<D extends Record<string, unknown>> {
|
||||
columns: Column<CollectionTableColumn>[]
|
||||
data: CollectionTableColumn[]
|
||||
hiddenColumns: IdType<D>[]
|
||||
classNames?: {
|
||||
td: string
|
||||
}
|
||||
}
|
||||
|
||||
export function Table<D extends Record<string, unknown>>({
|
||||
columns,
|
||||
data,
|
||||
hiddenColumns,
|
||||
classNames,
|
||||
...props
|
||||
}: TableProps<D>) {
|
||||
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, setHiddenColumns } = useTable(
|
||||
{
|
||||
columns,
|
||||
data,
|
||||
initialState: {
|
||||
sortBy: [
|
||||
{
|
||||
desc: true,
|
||||
id: ColumnHeaders.Volume,
|
||||
},
|
||||
],
|
||||
},
|
||||
...props,
|
||||
},
|
||||
useSortBy
|
||||
)
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
if (hiddenColumns && isMobile) {
|
||||
setHiddenColumns(hiddenColumns)
|
||||
} else {
|
||||
setHiddenColumns([])
|
||||
}
|
||||
}, [hiddenColumns, setHiddenColumns])
|
||||
|
||||
return (
|
||||
<table {...getTableProps()} className={styles.table}>
|
||||
<thead className={styles.thead}>
|
||||
{headerGroups.map((headerGroup) => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()} key={headerGroup.id}>
|
||||
{headerGroup.headers.map((column, index) => {
|
||||
return (
|
||||
<th
|
||||
className={styles.th}
|
||||
{...column.getHeaderProps(column.getSortByToggleProps())}
|
||||
style={{
|
||||
textAlign: index === 0 ? 'left' : 'right',
|
||||
paddingLeft: index === 0 ? '52px' : 0,
|
||||
}}
|
||||
key={index}
|
||||
>
|
||||
<Box as="span" color="accentAction" position="relative">
|
||||
{column.isSorted ? (
|
||||
column.isSortedDesc ? (
|
||||
<ArrowRightIcon style={{ transform: 'rotate(90deg)', position: 'absolute' }} />
|
||||
) : (
|
||||
<ArrowRightIcon style={{ transform: 'rotate(-90deg)', position: 'absolute' }} />
|
||||
)
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</Box>
|
||||
<Box as="span" paddingLeft={column.isSorted ? '18' : '0'}>
|
||||
{column.render('Header')}
|
||||
</Box>
|
||||
</th>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody {...getTableBodyProps()}>
|
||||
{rows.map((row, i) => {
|
||||
prepareRow(row)
|
||||
|
||||
return (
|
||||
<tr
|
||||
className={styles.tr}
|
||||
{...row.getRowProps()}
|
||||
key={i}
|
||||
onClick={() => navigate(`/nfts/collection/${row.original.collection.address}`)}
|
||||
>
|
||||
{row.cells.map((cell, cellIndex) => {
|
||||
return (
|
||||
<td className={clsx(styles.td, classNames?.td)} {...cell.getCellProps()} key={cellIndex}>
|
||||
{cellIndex === 0 ? <span className={styles.rank}>{i + 1}</span> : null}
|
||||
{cell.render('Cell')}
|
||||
</td>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
97
src/nft/components/explore/TrendingCollections.tsx
Normal file
97
src/nft/components/explore/TrendingCollections.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
import clsx from 'clsx'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useQuery } from 'react-query'
|
||||
|
||||
import { Box } from '../../components/Box'
|
||||
import { Column, Row } from '../../components/Flex'
|
||||
import { headlineMedium } from '../../css/common.css'
|
||||
import { fetchTrendingCollections } from '../../queries'
|
||||
import { CollectionTableColumn, TimePeriod, VolumeType } from '../../types'
|
||||
import CollectionTable from './CollectionTable'
|
||||
import * as styles from './Explore.css'
|
||||
|
||||
const timeOptions: { label: string; value: TimePeriod }[] = [
|
||||
{ label: '24 hour', value: TimePeriod.OneDay },
|
||||
{ label: '7 day', value: TimePeriod.SevenDays },
|
||||
{ label: '30 day', value: TimePeriod.ThirtyDays },
|
||||
{ label: 'All time', value: TimePeriod.AllTime },
|
||||
]
|
||||
|
||||
const TrendingCollections = () => {
|
||||
const [timePeriod, setTimePeriod] = useState<TimePeriod>(TimePeriod.OneDay)
|
||||
|
||||
const { isSuccess, data } = useQuery(
|
||||
['trendingCollections', timePeriod],
|
||||
() => {
|
||||
return fetchTrendingCollections({ volumeType: 'eth', timePeriod, size: 100 })
|
||||
},
|
||||
{
|
||||
refetchOnReconnect: false,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
refetchInterval: 5000,
|
||||
}
|
||||
)
|
||||
|
||||
const trendingCollections = useMemo(() => {
|
||||
if (isSuccess && data) {
|
||||
return data.map((d) => ({
|
||||
...d,
|
||||
collection: {
|
||||
name: d.name,
|
||||
logo: d.imageUrl,
|
||||
address: d.address,
|
||||
isVerified: d.isVerified,
|
||||
},
|
||||
volume: {
|
||||
value: d.volume,
|
||||
change: d.volumeChange,
|
||||
type: 'eth' as VolumeType,
|
||||
},
|
||||
floor: {
|
||||
value: d.floor,
|
||||
change: d.floorChange,
|
||||
},
|
||||
owners: {
|
||||
value: d.owners,
|
||||
change: d.ownersChange,
|
||||
},
|
||||
sales: d.sales,
|
||||
totalSupply: d.totalSupply,
|
||||
}))
|
||||
} else return [] as CollectionTableColumn[]
|
||||
}, [data, isSuccess])
|
||||
|
||||
return (
|
||||
<Box width="full" className={styles.section}>
|
||||
<Column width="full">
|
||||
<Row>
|
||||
<Box as="h2" className={headlineMedium} marginTop="88">
|
||||
Trending Collections
|
||||
</Box>
|
||||
</Row>
|
||||
<Row>
|
||||
<Box className={styles.trendingOptions}>
|
||||
{timeOptions.map((timeOption) => {
|
||||
return (
|
||||
<span
|
||||
className={clsx(
|
||||
styles.trendingOption,
|
||||
timeOption.value === timePeriod && styles.trendingOptionActive
|
||||
)}
|
||||
key={timeOption.value}
|
||||
onClick={() => setTimePeriod(timeOption.value)}
|
||||
>
|
||||
{timeOption.label}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Row>
|
||||
<Row paddingBottom="52">{data ? <CollectionTable data={trendingCollections} /> : <p>Loading</p>}</Row>
|
||||
</Column>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default TrendingCollections
|
@ -1,4 +1,5 @@
|
||||
import Banner from 'nft/components/explore/Banner'
|
||||
import TrendingCollections from 'nft/components/explore/TrendingCollections'
|
||||
import ValueProp from 'nft/components/explore/ValueProp'
|
||||
|
||||
const NftExplore = () => {
|
||||
@ -6,6 +7,7 @@ const NftExplore = () => {
|
||||
<>
|
||||
<Banner />
|
||||
<ValueProp />
|
||||
<TrendingCollections />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -3713,6 +3713,13 @@
|
||||
"@types/history" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-table@^7.7.12":
|
||||
version "7.7.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.7.12.tgz#628011d3cb695b07c678704a61f2f1d5b8e567fd"
|
||||
integrity sha512-bRUent+NR/WwtDGwI/BqhZ8XnHghwHw0HUKeohzB5xN3K2qKWYE5w19e7GCuOkL1CXD9Gi1HFy7TIm2AvgWUHg==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-virtualized-auto-sizer@^1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz#b3187dae1dfc4c15880c9cfc5b45f2719ea6ebd4"
|
||||
|
Loading…
Reference in New Issue
Block a user