ScrollableList: replace margins with padding

This commit is contained in:
Alex Gleason 2022-04-22 12:24:09 -05:00
parent a8c306e62b
commit ae48cb2c06
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
12 changed files with 41 additions and 14 deletions

View File

@ -6,10 +6,26 @@ import PullToRefresh from 'soapbox/components/pull-to-refresh';
import { Spinner, Text } from './ui'; import { Spinner, Text } from './ui';
type Context = {
itemClassName?: string,
listClassName?: string,
}
type VComponent = {
context?: Context,
}
// NOTE: It's crucial to space lists with **padding** instead of margin!
// Pass an `itemClassName` like `pb-3`, NOT a `space-y-3` className
// https://virtuoso.dev/troubleshooting#list-does-not-scroll-to-the-bottom--items-jump-around
const Item: React.FC<VComponent> = ({ context, ...rest }) => (
<div className={context?.itemClassName} {...rest} />
);
// Ensure the className winds up here // Ensure the className winds up here
const List = React.forwardRef((props: any, ref: React.ForwardedRef<HTMLDivElement>) => { const List = React.forwardRef<HTMLDivElement, VComponent>((props, ref) => {
const { context, ...rest } = props; const { context, ...rest } = props;
return <div ref={ref} className={context.listClassName} {...rest} />; return <div ref={ref} className={context?.listClassName} {...rest} />;
}); });
interface IScrollableList { interface IScrollableList {
@ -28,6 +44,7 @@ interface IScrollableList {
placeholderCount?: number, placeholderCount?: number,
onRefresh?: () => Promise<any>, onRefresh?: () => Promise<any>,
className?: string, className?: string,
itemClassName?: string,
} }
/** Legacy ScrollableList with Virtuoso for backwards-compatibility */ /** Legacy ScrollableList with Virtuoso for backwards-compatibility */
@ -43,6 +60,7 @@ const ScrollableList: React.FC<IScrollableList> = ({
onScrollToTop, onScrollToTop,
onLoadMore, onLoadMore,
className, className,
itemClassName,
hasMore, hasMore,
placeholderComponent: Placeholder, placeholderComponent: Placeholder,
placeholderCount = 0, placeholderCount = 0,
@ -101,12 +119,14 @@ const ScrollableList: React.FC<IScrollableList> = ({
itemContent={renderItem} itemContent={renderItem}
context={{ context={{
listClassName: className, listClassName: className,
itemClassName,
}} }}
components={{ components={{
Header: () => prepend, Header: () => prepend,
ScrollSeekPlaceholder: Placeholder as any, ScrollSeekPlaceholder: Placeholder as any,
EmptyPlaceholder: () => renderEmpty(), EmptyPlaceholder: () => renderEmpty(),
List, List,
Item,
}} }}
/> />
</PullToRefresh> </PullToRefresh>

View File

@ -1,3 +1,4 @@
import classNames from 'classnames';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
@ -222,7 +223,12 @@ export default class StatusList extends ImmutablePureComponent {
placeholderComponent={PlaceholderStatus} placeholderComponent={PlaceholderStatus}
placeholderCount={20} placeholderCount={20}
ref={this.setRef} ref={this.setRef}
className={divideType === 'border' ? 'divide-y divide-solid divide-gray-200 dark:divide-gray-800' : 'sm:space-y-3 divide-y divide-solid divide-gray-200 dark:divide-gray-800 sm:divide-none'} className={classNames('divide-y divide-solid divide-gray-200 dark:divide-slate-700', {
'sm:divide-none': divideType !== 'border',
})}
itemClassName={classNames({
'sm:pb-3': divideType !== 'border',
})}
{...other} {...other}
> >
{this.renderScrollableContent()} {this.renderScrollableContent()}

View File

@ -116,7 +116,8 @@ class UserIndex extends ImmutablePureComponent {
showLoading={showLoading} showLoading={showLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={intl.formatMessage(messages.empty)} emptyMessage={intl.formatMessage(messages.empty)}
className='mt-4 space-y-4' className='mt-4'
itemClassName='pb-4'
> >
{accountIds.map(id => {accountIds.map(id =>
<AccountContainer key={id} id={id} withDate />, <AccountContainer key={id} id={id} withDate />,

View File

@ -45,7 +45,7 @@ const Blocks: React.FC = () => {
onLoadMore={() => handleLoadMore(dispatch)} onLoadMore={() => handleLoadMore(dispatch)}
hasMore={hasMore} hasMore={hasMore}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
className='space-y-4' itemClassName='pb-4'
> >
{accountIds.map((id: string) => {accountIds.map((id: string) =>
<AccountContainer key={id} id={id} />, <AccountContainer key={id} id={id} />,

View File

@ -125,7 +125,7 @@ class Followers extends ImmutablePureComponent {
diffCount={diffCount} diffCount={diffCount}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />} emptyMessage={<FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />}
className='space-y-4' itemClassName='pb-4'
> >
{accountIds.map(id => {accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />, <AccountContainer key={id} id={id} withNote={false} />,

View File

@ -125,7 +125,7 @@ class Following extends ImmutablePureComponent {
diffCount={diffCount} diffCount={diffCount}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />} emptyMessage={<FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />}
className='space-y-4' itemClassName='pb-4'
> >
{accountIds.map(id => {accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />, <AccountContainer key={id} id={id} withNote={false} />,

View File

@ -45,7 +45,7 @@ const Mutes: React.FC = () => {
onLoadMore={() => handleLoadMore(dispatch)} onLoadMore={() => handleLoadMore(dispatch)}
hasMore={hasMore} hasMore={hasMore}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
className='space-y-4' itemClassName='pb-4'
> >
{accountIds.map((id: string) => {accountIds.map((id: string) =>
<AccountContainer key={id} id={id} />, <AccountContainer key={id} id={id} />,

View File

@ -28,7 +28,7 @@ const BirthdaysModal = ({ onClose }: IBirthdaysModal) => {
<ScrollableList <ScrollableList
scrollKey='reblogs' scrollKey='reblogs'
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
className='space-y-3' itemClassName='pb-3'
> >
{accountIds.map(id => {accountIds.map(id =>
<Account key={id} accountId={id} />, <Account key={id} accountId={id} />,

View File

@ -54,7 +54,7 @@ class FavouritesModal extends React.PureComponent {
<ScrollableList <ScrollableList
scrollKey='favourites' scrollKey='favourites'
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
className='space-y-3' itemClassName='pb-3'
> >
{accountIds.map(id => {accountIds.map(id =>
<AccountContainer key={id} id={id} />, <AccountContainer key={id} id={id} />,

View File

@ -61,7 +61,7 @@ class MentionsModal extends React.PureComponent {
body = ( body = (
<ScrollableList <ScrollableList
scrollKey='mentions' scrollKey='mentions'
className='space-y-3' itemClassName='pb-3'
> >
{accountIds.map(id => {accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />, <AccountContainer key={id} id={id} withNote={false} />,

View File

@ -87,7 +87,7 @@ const ReactionsModal: React.FC<IReactionsModal> = ({ onClose, statusId, ...props
<ScrollableList <ScrollableList
scrollKey='reactions' scrollKey='reactions'
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
className='space-y-3' itemClassName='pb-3'
> >
{accounts.map((account) => {accounts.map((account) =>
<AccountContainer key={`${account.id}-${account.reaction}`} id={account.id} /* reaction={account.reaction} */ />, <AccountContainer key={`${account.id}-${account.reaction}`} id={account.id} /* reaction={account.reaction} */ />,

View File

@ -72,7 +72,7 @@ class ReblogsModal extends React.PureComponent {
<ScrollableList <ScrollableList
scrollKey='reblogs' scrollKey='reblogs'
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
className='space-y-3' itemClassName='pb-3'
> >
{accountIds.map(id => {accountIds.map(id =>
<AccountContainer key={id} id={id} />, <AccountContainer key={id} id={id} />,