Skip to content

Commit f997f60

Browse files
author
Elson Correia
committed
fix tests, improve pagination and props
1 parent 7f74579 commit f997f60

File tree

11 files changed

+66
-74
lines changed

11 files changed

+66
-74
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "flatlist-react",
3-
"version": "1.5.2",
3+
"version": "1.5.3",
44
"description": "A helpful utility component to handle lists in react like a champ",
55
"main": "./lib/index.js",
66
"scripts": {

src/___subComponents/InfiniteLoader.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,12 @@ class InfiniteLoader extends Component<InfiniteLoaderProps, State> {
8989
this.state.scrollingContainer.scrollTop = this.lastScrollTop;
9090
}
9191

92-
// if prev and current loading are the same is because the component updated from props change
93-
// otherwise is because the component updated itself
92+
// reset loading state when the list size changes
9493
if (prevProps.itemsCount !== this.props.itemsCount) {
9594
this.reset();
9695
}
96+
97+
this.checkIfLoadingIsNeeded();
9798
}
9899

99100
componentWillUnmount(): void {
@@ -103,9 +104,7 @@ class InfiniteLoader extends Component<InfiniteLoaderProps, State> {
103104

104105
// update the loading flags and items count whether "hasMore" is false or list changed
105106
reset(): void {
106-
this.setState({ loading: false }, () => {
107-
this.checkIfLoadingIsNeeded();
108-
});
107+
this.setState({ loading: false });
109108
}
110109

111110
getScrollingContainerChildrenCount = (): number => {
@@ -166,22 +165,24 @@ class InfiniteLoader extends Component<InfiniteLoaderProps, State> {
166165
}
167166
};
168167

169-
render(): JSX.Element {
168+
render(): ReactNode {
170169
const { loading } = this.state;
171170
const { hasMore, loadingIndicator, loadingIndicatorPosition } = this.props;
172171

172+
const spinning = hasMore && loading;
173+
173174
// do not remove the element from the dom so the ref is not broken but set it invisible enough
174175
const styles: CSSProperties = {
175176
display: "flex",
176-
height: hasMore ? "auto" : 0,
177+
height: spinning ? "auto" : 0,
177178
justifyContent:
178179
loadingIndicatorPosition === "center"
179180
? loadingIndicatorPosition
180181
: loadingIndicatorPosition === "right"
181182
? "flex-end"
182183
: "flex-start",
183-
padding: hasMore ? "5px 0" : 0,
184-
visibility: loading && hasMore ? "visible" : "hidden",
184+
padding: spinning ? "5px 0" : 0,
185+
visibility: spinning ? "visible" : "hidden",
185186
};
186187

187188
const loadingEl = isFunction(loadingIndicator)
@@ -194,7 +195,7 @@ class InfiniteLoader extends Component<InfiniteLoaderProps, State> {
194195
className="__infinite-loader"
195196
style={styles}
196197
>
197-
{hasMore && (loadingIndicator ? loadingEl : <DefaultLoadIndicator />)}
198+
{spinning && (loadingIndicator ? loadingEl : <DefaultLoadIndicator />)}
198199
</div>
199200
);
200201
}

src/___subComponents/PlainList.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { array, bool, func, node, object, oneOfType, string } from "prop-types";
2-
import React, { forwardRef, Ref } from "react";
2+
import React, { forwardRef, ReactNode, Ref } from "react";
33
import convertListToArray from "../___utils/convertListToArray";
44
import { isString } from "../___utils/isType";
55
import { listItem } from "../flatListProps";
@@ -9,8 +9,8 @@ import { handleRenderItem, renderBlank, renderFunc } from "./uiFunctions";
99

1010
export interface PlainListProps {
1111
list: listItem[];
12-
renderItem: JSX.Element | renderFunc;
13-
renderWhenEmpty?: null | (() => JSX.Element);
12+
renderItem: ReactNode | renderFunc;
13+
renderWhenEmpty?: ReactNode | (() => JSX.Element);
1414
wrapperHtmlTag?: string;
1515
renderOnScroll?: boolean;
1616
forwardRef?: Ref<HTMLElement>;

src/___subComponents/ScrollRenderer.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { any, arrayOf, element, func, node, oneOfType } from "prop-types";
22
import React, {
33
createRef,
4+
ReactNode,
45
Ref,
56
useEffect,
67
useLayoutEffect,
@@ -17,8 +18,8 @@ interface Props {
1718
list: any[];
1819
renderItem: renderItem;
1920
groupSeparator:
20-
| JSX.Element
21-
| ((g: any, idx: number, label: string) => JSX.Element | null)
21+
| ReactNode
22+
| ((g: any, idx: number, label: string) => ReactNode | null)
2223
| null;
2324
}
2425

src/___subComponents/ScrollToTopButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import {
77
oneOfType,
88
shape,
99
} from "prop-types";
10-
import React, { createRef, Ref, useEffect, useState } from "react";
10+
import React, { createRef, ReactNode, Ref, useEffect, useState } from "react";
1111
import { isFunction } from "../___utils/isType";
1212
import { btnPosition } from "./uiFunctions";
1313

1414
interface Props {
15-
button: JSX.Element | (() => JSX.Element);
15+
button: ReactNode | (() => ReactNode);
1616
position: string;
1717
offset: number;
1818
padding: number;
@@ -22,7 +22,7 @@ interface Props {
2222
function ScrollToTopButton(props: Props) {
2323
const anchor: Ref<HTMLElement> = createRef();
2424
const { button, position, padding, offset, scrollingContainer } = props;
25-
const btn = isFunction(button) ? (button as () => JSX.Element)() : button;
25+
const btn = isFunction(button) ? (button as () => ReactNode)() : button;
2626
const [mounted, setMounted] = useState(false);
2727

2828
useEffect(() => {

src/___subComponents/uiFunctions.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@ import React, { cloneElement, Component, FC, ReactNode } from "react";
22
import { isArray, isFunction } from "../___utils/isType";
33
import DefaultBlank from "./DefaultBlank";
44

5-
export type renderFunc = (item: any, key: number | string) => ReactNode;
5+
export type renderFunc = (
6+
item: any,
7+
key: number | string
8+
) => ReactNode | JSX.Element;
69

7-
export type renderItemCallback = (item: any, idx: number | string) => ReactNode;
810
export type renderItem =
911
| ReactNode
10-
| FC
12+
| FC<any>
1113
| Component
1214
| renderFunc
13-
| renderItemCallback;
15+
| JSX.Element;
1416

1517
export const renderBlank = (
16-
renderWhenEmpty: null | (() => JSX.Element) = null
18+
renderWhenEmpty: ReactNode | (() => JSX.Element) = null
1719
): JSX.Element =>
1820
renderWhenEmpty && isFunction(renderWhenEmpty)
19-
? renderWhenEmpty()
21+
? (renderWhenEmpty as () => JSX.Element)()
2022
: DefaultBlank();
2123

2224
export const handleRenderGroupSeparator = (CustomSeparator: any) =>
@@ -49,8 +51,8 @@ export const handleRenderItem =
4951
renderItem: renderItem,
5052
renderSeparator:
5153
| null
52-
| ((s: string, i: number | string) => JSX.Element) = null
53-
): renderFunc | ReactNode =>
54+
| ((s: string, i: number | string) => ReactNode) = null
55+
): renderFunc =>
5456
(item: any, key: number | string) => {
5557
if (!renderItem) {
5658
return null;
@@ -60,12 +62,12 @@ export const handleRenderItem =
6062

6163
if (isArray(item) && item[0] === "___list-separator") {
6264
return renderSeparator
63-
? (renderSeparator as renderItemCallback)(item, itemId)
65+
? (renderSeparator as renderFunc)(item, itemId)
6466
: null;
6567
}
6668

6769
if (isFunction(renderItem)) {
68-
return (renderItem as renderItemCallback)(item, itemId);
70+
return (renderItem as renderFunc)(item, itemId);
6971
}
7072

7173
const comp = renderItem as JSX.Element;

src/___subComponents/withList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import limitList from "../___utils/limitList";
77
import reverseList from "../___utils/reverseList";
88
import searchList from "../___utils/searchList";
99
import sortList from "../___utils/sortList";
10-
import { defaultProps, FlatListProps } from "../flatListProps";
10+
import { defaultProps, FlatListProps, SortInterface } from "../flatListProps";
1111
import { renderBlank } from "./uiFunctions";
1212

1313
const withList = (List: any): FC<FlatListProps> => {
@@ -88,7 +88,7 @@ const withList = (List: any): FC<FlatListProps> => {
8888
}
8989

9090
const sortOptions = {
91-
...defaultProps.sort,
91+
...(defaultProps.sort as SortInterface),
9292
...sort,
9393
};
9494
if (sortOptions.by || sortBy || (isBoolean(sort) && sort)) {

src/flatListProps.ts

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
1-
import {
2-
array,
3-
arrayOf,
4-
bool,
5-
element,
6-
func,
7-
node,
8-
number,
9-
object,
10-
oneOf,
11-
oneOfType,
12-
Requireable,
13-
shape,
14-
string
15-
} from 'prop-types';
16-
import {Component, FC, ReactNode, Ref} from 'react';
1+
import {array, arrayOf, bool, element, func, node, number, object, oneOf, oneOfType, Requireable, shape, string} from 'prop-types';
2+
import {ReactNode, Ref} from 'react';
173
import warning from 'warning';
184
import {DisplayHandlerProps, DisplayInterface} from './___subComponents/DisplayHandler';
195
import {InfiniteLoaderInterface} from './___subComponents/InfiniteLoader';
20-
import {renderFunc, renderItem} from './___subComponents/uiFunctions';
6+
import {renderItem} from './___subComponents/uiFunctions';
217
import {GroupOptionsInterface} from './___utils/groupList';
228
import {SearchOptionsInterface} from './___utils/searchList';
239
import {SortOptionsInterface} from './___utils/sortList';
@@ -39,20 +25,20 @@ function deprecated(propType: Requireable<unknown>, defaultVal: unknown, alterna
3925
};
4026
}
4127

42-
export type listItem = {id?: string | number} | unknown;
28+
export type listItem = Array<{id?: string | number, [key: string]: any} | any> | Set<any> | Map<any, any> | {id?: string | number, [key: string]: any};
4329

4430
export interface GroupInterface extends GroupOptionsInterface {
4531
of?: number;
4632
// eslint-disable-next-line @typescript-eslint/no-explicit-any
47-
separator?: JSX.Element | ((g: any, idx: number, label: string) => JSX.Element | null) | null;
33+
separator?: ReactNode | ((g: any, idx: number, label: string) => ReactNode | null) | null;
4834
separatorAtTheBottom?: boolean;
4935
sortBy?: SortOptionsInterface['by'];
5036
sortDescending?: boolean;
5137
sortCaseInsensitive?: boolean;
5238
}
5339

5440
export interface ScrollToTopInterface {
55-
button?: JSX.Element | (() => JSX.Element);
41+
button?: ReactNode | (() => JSX.Element);
5642
offset?: number;
5743
padding?: number;
5844
position?: string;
@@ -67,9 +53,9 @@ export interface SortInterface extends SortOptionsInterface {
6753
export interface FlatListProps {
6854
__forwarededRef?: Ref<HTMLElement>;
6955
// RENDER
70-
list: listItem[];
56+
list: listItem;
7157
renderItem: renderItem;
72-
renderWhenEmpty?: null | (() => JSX.Element);
58+
renderWhenEmpty?: ReactNode | (() => JSX.Element);
7359
renderOnScroll?: boolean;
7460
limit?: number | string;
7561
reversed?: boolean;
@@ -119,7 +105,7 @@ export interface FlatListProps {
119105
paginationLoadingIndicatorPosition?: InfiniteLoaderInterface['loadingIndicatorPosition'];
120106
// scrollToTop
121107
scrollToTop?: boolean | ScrollToTopInterface;
122-
scrollToTopButton?: JSX.Element | (() => JSX.Element);
108+
scrollToTopButton?: ReactNode | (() => ReactNode);
123109
scrollToTopOffset?: number;
124110
scrollToTopPadding?: number;
125111
scrollToTopPosition?: string;
@@ -128,9 +114,11 @@ export interface FlatListProps {
128114
[key: string]: any;
129115
}
130116

131-
export const defaultProps = {
117+
export const defaultProps: FlatListProps = {
132118
__forwarededRef: {current: null},
133119
// RENDER
120+
list: [],
121+
renderItem: null,
134122
limit: 0,
135123
renderWhenEmpty: null,
136124
reversed: false,
@@ -154,18 +142,14 @@ export const defaultProps = {
154142
// GROUPS
155143
group: {
156144
by: '',
157-
limit: 0, // deprecated
145+
limit: 0,
158146
of: 0,
159147
reversed: false,
160148
separator: null,
161149
separatorAtTheBottom: false,
162-
sortedBy: '',
163-
sortBy: '', // deprecated
164-
sorted: false,
165-
sortedCaseInsensitive: false,
166-
sortCaseInsensitive: false, // deprecated
167-
sortedDescending: false,
168-
sortDescending: false // deprecated
150+
sortBy: '',
151+
sortCaseInsensitive: false,
152+
sortDescending: false
169153
},
170154
groupBy: '',
171155
groupOf: 0,
@@ -260,7 +244,7 @@ export const propTypes = {
260244
// GROUPS
261245
group: shape({
262246
by: oneOfType([func, string]),
263-
limit: deprecated(number, defaultProps.group.limit, 'group.of'), // deprecated
247+
limit: deprecated(number, defaultProps.group?.limit, 'group.of'), // deprecated
264248
of: number,
265249
reversed: bool,
266250
separator: oneOfType([node, func, element]),
@@ -272,11 +256,11 @@ export const propTypes = {
272256
sortBy: deprecated(oneOfType([
273257
string,
274258
arrayOf(oneOfType([string, shape({by: string, caseInsensitive: bool, descending: bool})]))
275-
]), defaultProps.group.sortBy, 'sortedBy'), // deprecated
259+
]), defaultProps?.group?.sortBy, 'sortedBy'), // deprecated
276260
sortedCaseInsensitive: bool,
277-
sortCaseInsensitive: deprecated(bool, defaultProps.group.sortCaseInsensitive, 'sortedCaseInsensitive'), // deprecated
261+
sortCaseInsensitive: deprecated(bool, defaultProps.group?.sortCaseInsensitive, 'sortedCaseInsensitive'), // deprecated
278262
sortedDescending: bool,
279-
sortDescending: deprecated(bool, defaultProps.group.sortDescending, 'sortedDescending') // deprecated
263+
sortDescending: deprecated(bool, defaultProps.group?.sortDescending, 'sortedDescending') // deprecated
280264
}),
281265
groupBy: oneOfType([func, string]),
282266
groupOf: number,
@@ -324,7 +308,7 @@ export const propTypes = {
324308
arrayOf(oneOfType([string, shape({by: string, caseInsensitive: bool})]))
325309
]),
326310
caseInsensitive: bool,
327-
everyWord: deprecated(bool, defaultProps.search.everyWord, 'search.onEveryWord'), // deprecated
311+
everyWord: deprecated(bool, defaultProps.search?.everyWord, 'search.onEveryWord'), // deprecated
328312
onEveryWord: bool,
329313
minCharactersCount: number,
330314
term: string

src/flatlist-react.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ import withList from './___subComponents/withList';
88
import {isString} from './___utils/isType';
99
import {defaultProps, FlatListProps, GroupInterface, propTypes, ScrollToTopInterface} from './flatListProps';
1010

11-
function FlatList(props: FlatListProps): JSX.Element {
11+
interface Props extends FlatListProps {
12+
list: any[]; // withList changes the list to array of anything
13+
}
14+
15+
function FlatList(props: Props): JSX.Element {
1216
const {
13-
list, renderWhenEmpty, wrapperHtmlTag, renderItem = null, renderOnScroll, // render/list related props
17+
list, renderWhenEmpty = null, wrapperHtmlTag, renderItem = null, renderOnScroll, // render/list related props
1418
group = {} as GroupInterface, groupSeparator, // group props
1519
display = {} as DisplayInterface, displayRow, rowGap, displayGrid, gridGap, minColumnWidth, // display props,
1620
hasMoreItems, loadMoreItems, paginationLoadingIndicator, paginationLoadingIndicatorPosition,
17-
scrollToTop, scrollToTopButton, scrollToTopPadding, scrollToTopOffset, scrollToTopPosition,
21+
scrollToTop, scrollToTopButton = null, scrollToTopPadding, scrollToTopOffset, scrollToTopPosition,
1822
pagination = {} as InfiniteLoaderInterface, // pagination props
1923
__forwarededRef,
2024
...otherProps
@@ -97,7 +101,7 @@ FlatList.propTypes = propTypes;
97101

98102
FlatList.defaultProps = defaultProps;
99103

100-
export default memo<FlatListProps>(withList(forwardRef((props: FlatListProps, ref: Ref<HTMLElement>) => {
104+
export default memo<FlatListProps>(withList(forwardRef((props: Props, ref: Ref<HTMLElement>) => {
101105
ref = ref || createRef();
102106
return (
103107
<FlatList {...props} __forwarededRef={ref}/>

tests/FlatList.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ describe('FlatList', () => {
378378
group={{
379379
by: groupByFn,
380380
separator: sep,
381-
sortedBy: 'age'
381+
sortBy: 'age'
382382
}}
383383
/>
384384
);

0 commit comments

Comments
 (0)