@codeleap/web 3.12.5 → 3.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -30,7 +30,7 @@ const defaultProps: Partial<GridProps> = {
|
|
|
30
30
|
columnItemsSpacing: 8,
|
|
31
31
|
rowItemsSpacing: 8,
|
|
32
32
|
overscan: 2,
|
|
33
|
-
|
|
33
|
+
reloadTimeout: 350,
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function Grid<T = any>(props: GridProps<T>) {
|
|
@@ -52,7 +52,7 @@ export function Grid<T = any>(props: GridProps<T>) {
|
|
|
52
52
|
separators,
|
|
53
53
|
masonryProps = {},
|
|
54
54
|
numColumns,
|
|
55
|
-
|
|
55
|
+
reloadTimeout,
|
|
56
56
|
} = allProps
|
|
57
57
|
|
|
58
58
|
const variantStyles = useDefaultComponentStyle<'u:Grid', typeof GridPresets>('u:Grid', {
|
|
@@ -101,15 +101,14 @@ export function Grid<T = any>(props: GridProps<T>) {
|
|
|
101
101
|
<ListMasonry
|
|
102
102
|
items={data}
|
|
103
103
|
render={renderItem}
|
|
104
|
-
itemKey={item => item?.id}
|
|
104
|
+
itemKey={(item, _index) => (item?.id ?? _index)}
|
|
105
105
|
columnGutter={columnItemsSpacing}
|
|
106
106
|
rowGutter={rowItemsSpacing}
|
|
107
107
|
columnCount={numColumns}
|
|
108
108
|
maxColumnCount={numColumns}
|
|
109
109
|
onRender={onLoadMore}
|
|
110
110
|
overscanBy={overscan}
|
|
111
|
-
|
|
112
|
-
itemsRehydrateIndicator={enabledItemsRehydrateIndicator}
|
|
111
|
+
reloadTimeout={reloadTimeout}
|
|
113
112
|
{...masonryProps}
|
|
114
113
|
/>
|
|
115
114
|
</ListLayout>
|
|
@@ -33,7 +33,7 @@ const defaultProps: Partial<ListProps> = {
|
|
|
33
33
|
refresh: true,
|
|
34
34
|
rowItemsSpacing: 8,
|
|
35
35
|
overscan: 2,
|
|
36
|
-
|
|
36
|
+
reloadTimeout: 350,
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function List<T = any>(props: ListProps<T>) {
|
|
@@ -53,7 +53,7 @@ export function List<T = any>(props: ListProps<T>) {
|
|
|
53
53
|
overscan,
|
|
54
54
|
separators,
|
|
55
55
|
masonryProps = {},
|
|
56
|
-
|
|
56
|
+
reloadTimeout,
|
|
57
57
|
} = allProps
|
|
58
58
|
|
|
59
59
|
const variantStyles = useDefaultComponentStyle<'u:List', typeof ListPresets>('u:List', {
|
|
@@ -62,7 +62,7 @@ export function List<T = any>(props: ListProps<T>) {
|
|
|
62
62
|
styles,
|
|
63
63
|
})
|
|
64
64
|
|
|
65
|
-
const { layoutProps, onLoadMore
|
|
65
|
+
const { layoutProps, onLoadMore } = useInfiniteScroll(allProps)
|
|
66
66
|
|
|
67
67
|
const separator = React.useMemo(() => {
|
|
68
68
|
return separators ? <ListSeparatorComponent separatorStyles={variantStyles.separator} /> : null
|
|
@@ -100,13 +100,12 @@ export function List<T = any>(props: ListProps<T>) {
|
|
|
100
100
|
<ListMasonry
|
|
101
101
|
items={data}
|
|
102
102
|
render={renderItem}
|
|
103
|
-
itemKey={item => item?.id}
|
|
103
|
+
itemKey={(item, _index) => (item?.id ?? _index)}
|
|
104
104
|
rowGutter={rowItemsSpacing}
|
|
105
105
|
onRender={onLoadMore}
|
|
106
106
|
overscanBy={overscan}
|
|
107
107
|
columnCount={1}
|
|
108
|
-
|
|
109
|
-
itemsRehydrateIndicator={enabledItemsRehydrateIndicator}
|
|
108
|
+
reloadTimeout={reloadTimeout}
|
|
110
109
|
{...masonryProps}
|
|
111
110
|
/>
|
|
112
111
|
</ListLayout>
|
|
@@ -5,10 +5,10 @@ import { ListComposition, ListPresets } from './styles'
|
|
|
5
5
|
import { motion } from 'framer-motion'
|
|
6
6
|
import { ActivityIndicatorProps } from '../ActivityIndicator'
|
|
7
7
|
import { ComponentCommonProps } from '../../types'
|
|
8
|
-
import { RenderComponentProps, ListProps as ListMasonryProps } from 'masonic'
|
|
9
8
|
import { UseInfiniteScrollArgs } from './useInfiniteScroll'
|
|
9
|
+
import { ItemMasonryProps, ListMasonryProps } from '../../lib'
|
|
10
10
|
|
|
11
|
-
export type AugmentedRenderItemInfo<T> =
|
|
11
|
+
export type AugmentedRenderItemInfo<T> = ItemMasonryProps<T> & {
|
|
12
12
|
item: T
|
|
13
13
|
isFirst: boolean
|
|
14
14
|
isLast: boolean
|
|
@@ -50,6 +50,6 @@ Data = T extends Array<infer D> ? D : never
|
|
|
50
50
|
ref?: React.MutableRefObject<undefined>
|
|
51
51
|
rowItemsSpacing?: number
|
|
52
52
|
overscan?: number
|
|
53
|
-
masonryProps?: Partial<ListMasonryProps<T>>
|
|
54
|
-
|
|
53
|
+
masonryProps?: Partial<Omit<ListMasonryProps<T>, 'previousItemsLength'>>
|
|
54
|
+
reloadTimeout?: number
|
|
55
55
|
} & ComponentCommonProps & UseInfiniteScrollArgs
|
package/src/lib/ListMasonry.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { useWindowSize } from '@react-hook/window-size'
|
|
3
|
-
import {
|
|
3
|
+
import { TypeGuards } from '@codeleap/common'
|
|
4
|
+
import { EmptyPlaceholder } from '../components/EmptyPlaceholder'
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
useMasonry,
|
|
@@ -12,39 +13,69 @@ import {
|
|
|
12
13
|
RenderComponentProps,
|
|
13
14
|
} from 'masonic'
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
function fillItems(arr: Array<any>, toCount: number, fillContent = {}) {
|
|
17
|
+
if (!arr || !TypeGuards.isArray(arr)) return []
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
if (toCount === arr?.length) return arr
|
|
20
|
+
|
|
21
|
+
const diff = toCount - arr?.length
|
|
22
|
+
|
|
23
|
+
if (diff < 0) return arr
|
|
24
|
+
|
|
25
|
+
const right = Array(diff).fill(fillContent)
|
|
26
|
+
|
|
27
|
+
return arr.concat(right)
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
type UseMasonryReloadArgs = {
|
|
31
|
+
data: Array<any>
|
|
32
|
+
reloadTimeout: number
|
|
33
|
+
}
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
export const useMasonryReload = (args: UseMasonryReloadArgs) => {
|
|
36
|
+
const {
|
|
37
|
+
data,
|
|
38
|
+
reloadTimeout = 350,
|
|
39
|
+
} = args
|
|
26
40
|
|
|
27
|
-
const
|
|
41
|
+
const [reloadingLayout, setReloadingLayout] = React.useState(false)
|
|
42
|
+
const previousLengthRef = React.useRef(data?.length ?? 0)
|
|
28
43
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
length: data?.length
|
|
33
|
-
})
|
|
44
|
+
const updater = () => {
|
|
45
|
+
previousLengthRef.current = (data?.length ?? 0)
|
|
46
|
+
}
|
|
34
47
|
|
|
35
|
-
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
if (previousLengthRef.current > data?.length) {
|
|
36
50
|
setReloadingLayout(true)
|
|
37
51
|
|
|
38
|
-
console.log({
|
|
39
|
-
reloaded: true,
|
|
40
|
-
})
|
|
41
|
-
|
|
42
52
|
setTimeout(() => {
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
updater()
|
|
54
|
+
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
setReloadingLayout(false)
|
|
57
|
+
}, reloadTimeout)
|
|
58
|
+
}, reloadTimeout)
|
|
59
|
+
} else {
|
|
60
|
+
updater()
|
|
45
61
|
}
|
|
46
|
-
}, [data?.length
|
|
62
|
+
}, [data?.length])
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
reloadingLayout,
|
|
66
|
+
setReloadingLayout,
|
|
67
|
+
previousLength: previousLengthRef.current,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type ItemMasonryProps<T> = RenderComponentProps<T>
|
|
47
72
|
|
|
73
|
+
export type ListMasonryProps<T> = MasonryProps<T> & {
|
|
74
|
+
previousItemsLength: number
|
|
75
|
+
reloadTimeout: UseMasonryReloadArgs['reloadTimeout']
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function MasonryComponent<Item>(props: ListMasonryProps<Item>) {
|
|
48
79
|
const containerRef = React.useRef(null)
|
|
49
80
|
|
|
50
81
|
const windowSize = useWindowSize({
|
|
@@ -72,22 +103,41 @@ export function ListMasonry<Item>(props: ListMasonryProps<Item>) {
|
|
|
72
103
|
columnCount: listProps?.columnCount,
|
|
73
104
|
maxColumnCount: listProps?.columnCount,
|
|
74
105
|
rowGutter: listProps?.rowGutter
|
|
75
|
-
}
|
|
106
|
+
})
|
|
76
107
|
|
|
77
108
|
const { scrollTop, isScrolling } = useScroller(listProps?.offset, listProps?.scrollFps)
|
|
78
109
|
|
|
79
110
|
const resizeObserver = useResizeObserver(positioner)
|
|
80
111
|
|
|
81
|
-
if (reloadingLayout) {
|
|
82
|
-
return <div><p>Loading</p></div>
|
|
83
|
-
}
|
|
84
|
-
|
|
85
112
|
return useMasonry({
|
|
86
113
|
...listProps,
|
|
87
114
|
resizeObserver,
|
|
88
115
|
positioner,
|
|
89
116
|
scrollTop,
|
|
90
117
|
isScrolling,
|
|
91
|
-
items:
|
|
118
|
+
items: fillItems(props?.items, props?.previousItemsLength)
|
|
92
119
|
})
|
|
93
120
|
}
|
|
121
|
+
|
|
122
|
+
export function ListMasonry<Item>(props: Omit<ListMasonryProps<Item>, 'previousItemsLength'>) {
|
|
123
|
+
const data = props?.items || []
|
|
124
|
+
|
|
125
|
+
const { reloadingLayout, previousLength } = useMasonryReload({
|
|
126
|
+
data,
|
|
127
|
+
reloadTimeout: props?.reloadTimeout,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
if (reloadingLayout) {
|
|
131
|
+
return (
|
|
132
|
+
<EmptyPlaceholder loading title={''} description={null} />
|
|
133
|
+
)
|
|
134
|
+
} else {
|
|
135
|
+
return (
|
|
136
|
+
<MasonryComponent
|
|
137
|
+
{...props}
|
|
138
|
+
items={data}
|
|
139
|
+
previousItemsLength={previousLength}
|
|
140
|
+
/>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
}
|