@fountain-ui/lab 2.0.0-beta.32 → 2.0.0-beta.34
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/build/commonjs/ComicViewer/ComicViewer.js +20 -6
- package/build/commonjs/ComicViewer/ComicViewer.js.map +1 -1
- package/build/commonjs/ComicViewer/ComicViewerProps.js +2 -2
- package/build/commonjs/ComicViewer/ComicViewerProps.js.map +1 -1
- package/build/commonjs/ComicViewer/ViewerItem.js +63 -32
- package/build/commonjs/ComicViewer/ViewerItem.js.map +1 -1
- package/build/module/ComicViewer/ComicViewer.js +20 -6
- package/build/module/ComicViewer/ComicViewer.js.map +1 -1
- package/build/module/ComicViewer/ComicViewerProps.js +2 -2
- package/build/module/ComicViewer/ComicViewerProps.js.map +1 -1
- package/build/module/ComicViewer/ViewerItem.js +64 -34
- package/build/module/ComicViewer/ViewerItem.js.map +1 -1
- package/build/typescript/ComicViewer/ComicViewerProps.d.ts +10 -2
- package/package.json +2 -2
- package/src/ComicViewer/ComicViewer.tsx +30 -11
- package/src/ComicViewer/ComicViewerProps.ts +12 -2
- package/src/ComicViewer/ViewerItem.tsx +86 -58
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["STATE","
|
|
1
|
+
{"version":3,"names":["STATE","INIT","URL_LOADED","LOADED","FAIL"],"sources":["ComicViewerProps.ts"],"sourcesContent":["import React from 'react';\nimport { ComponentProps } from '@fountain-ui/core';\nimport { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';\n\nexport const STATE = {\n INIT: 'init',\n URL_LOADED: 'url_loaded',\n LOADED: 'loaded',\n FAIL: 'fail',\n} as const;\n\nexport type LoadingState = typeof STATE[keyof typeof STATE];\n\nexport interface ComicViewerItemState{\n /**\n * Comic viewer item sortKey.\n */\n sortKey: number;\n\n /**\n * Content's loading state.\n */\n state: LoadingState;\n\n /***\n * Content's error Info.\n */\n error?: ErrorInfo;\n}\n\nexport interface ErrorInfo {\n /**\n * ComicViewerItemData.sortKey.\n */\n sortKey: number;\n\n /**\n * Number of times an error occurred.\n */\n count: number;\n\n /**\n * Content is Expired: true\n */\n expired: boolean;\n}\n\nexport type ComicViewerItemData<T = {}> = T & {\n /**\n * Image height.\n */\n height: number;\n\n /**\n * Unique value for identifying.\n */\n id: number | undefined;\n\n /**\n * Image sourceUrl for displaying.\n */\n url: string;\n\n /**\n * Image width.\n */\n width: number;\n\n /**\n * SortKey\n */\n sortKey: number;\n\n /**\n * Image expire date.\n */\n expiresAt: string;\n\n /***\n * Timestamp when get content response\n */\n responseTimestamp: number;\n}\n\nexport default interface ComicViewerProps<T> extends ComponentProps <{\n /**\n * Data for render.\n */\n data: ComicViewerItemData<T>[];\n\n /**\n * Delay Time to call the error handler.\n * @default 500\n */\n errorDebounceMillis?: number;\n\n /**\n * How many times retry onError when same item error occur\n * @default 3\n */\n errorRetryCount?: number;\n\n /**\n * How many items to render in the initial batch.\n * @default 1\n */\n initialNumToRender?: number;\n\n /**\n * Start at initialScrollPercentage.\n * If over 100, scroll to end.\n * @default 0\n */\n initialScrollPercentage?: number;\n\n /**\n * The value for FlatList viewabilityConfig.itemVisiblePercentThreshold.\n * @default 0\n */\n itemVisiblePercentThreshold?: number;\n\n /***\n * Timestamp when get content response\n */\n responseTimestamp: number;\n\n /**\n * Comic viewer width.\n */\n viewerWidth: number;\n\n /**\n * The value for FlatList windowSize.\n * @default 3\n */\n windowSize?: number;\n\n /**\n * How many images in one page.\n */\n pageUnit: number;\n\n /**\n * Method for getting next page contents.\n * @param sortKey\n */\n getNextPage?: (sortKey: number) => void;\n\n /**\n * Handling all viewerItem errors at once.\n * @param errors Array of ViewerItems errorInfo.\n */\n onError?: (errors: ErrorInfo[]) => void;\n\n /**\n * Handle scroll event.\n * @param event Scroll event.\n */\n onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\n\n /**\n * Handle item press event.\n */\n onItemPress?: () => void;\n\n /**\n * Component for comic viewer footer.\n */\n ListFooterComponent?: React.ReactElement;\n}> {}"],"mappings":"AAIA,OAAO,MAAMA,KAAK,GAAG;EACjBC,IAAI,EAAE,MADW;EAEjBC,UAAU,EAAE,YAFK;EAGjBC,MAAM,EAAE,QAHS;EAIjBC,IAAI,EAAE;AAJW,CAAd"}
|
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ImageBackground, Platform, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import * as R from 'ramda';
|
|
4
|
-
import { IconButton, Image, Spacer
|
|
4
|
+
import { IconButton, Image, Spacer } from '@fountain-ui/core';
|
|
5
5
|
import { Restart } from '@fountain-ui/icons';
|
|
6
|
+
import { STATE } from './ComicViewerProps';
|
|
6
7
|
|
|
7
8
|
const useStyles = function () {
|
|
8
|
-
const theme = useTheme();
|
|
9
9
|
return {
|
|
10
10
|
root: {
|
|
11
11
|
display: 'flex',
|
|
12
12
|
flexDirection: 'row',
|
|
13
13
|
justifyContent: 'center'
|
|
14
14
|
},
|
|
15
|
-
init: {
|
|
16
|
-
backgroundColor: theme.palette.paper.grey
|
|
17
|
-
},
|
|
18
|
-
failed: {
|
|
19
|
-
backgroundColor: theme.palette.paper.grey
|
|
20
|
-
},
|
|
21
15
|
reload: {
|
|
22
|
-
backgroundColor: theme.palette.paper.grey,
|
|
23
16
|
display: 'flex',
|
|
24
17
|
alignItems: 'center'
|
|
25
18
|
}
|
|
@@ -39,6 +32,7 @@ function ViewerItem(_ref) {
|
|
|
39
32
|
itemState,
|
|
40
33
|
isViewable,
|
|
41
34
|
sortKey,
|
|
35
|
+
responseTimestamp,
|
|
42
36
|
url,
|
|
43
37
|
width,
|
|
44
38
|
getNextPage,
|
|
@@ -53,7 +47,7 @@ function ViewerItem(_ref) {
|
|
|
53
47
|
errorCount.current = 0;
|
|
54
48
|
setIsLoaded(true);
|
|
55
49
|
onLoaded && onLoaded(sortKey);
|
|
56
|
-
}, [sortKey]);
|
|
50
|
+
}, [sortKey, onLoaded]);
|
|
57
51
|
const handleError = useCallback(() => {
|
|
58
52
|
errorCount.current = errorCount.current + 1;
|
|
59
53
|
const now = new Date();
|
|
@@ -64,7 +58,7 @@ function ViewerItem(_ref) {
|
|
|
64
58
|
count: errorCount.current,
|
|
65
59
|
expired
|
|
66
60
|
});
|
|
67
|
-
}, [errorCount.current]);
|
|
61
|
+
}, [errorCount.current, onError]);
|
|
68
62
|
const onReloadPress = useCallback(() => {
|
|
69
63
|
errorCount.current = 1;
|
|
70
64
|
onError && onError({
|
|
@@ -72,8 +66,17 @@ function ViewerItem(_ref) {
|
|
|
72
66
|
count: errorCount.current,
|
|
73
67
|
expired: false
|
|
74
68
|
});
|
|
75
|
-
}, [sortKey]);
|
|
69
|
+
}, [sortKey, onError]);
|
|
76
70
|
const viewStyle = {
|
|
71
|
+
width: '100%',
|
|
72
|
+
height,
|
|
73
|
+
...Platform.select({
|
|
74
|
+
web: {
|
|
75
|
+
'cursor': 'default'
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
};
|
|
79
|
+
const imageStyle = {
|
|
77
80
|
width,
|
|
78
81
|
height
|
|
79
82
|
};
|
|
@@ -83,14 +86,22 @@ function ViewerItem(_ref) {
|
|
|
83
86
|
failed
|
|
84
87
|
} = props;
|
|
85
88
|
|
|
86
|
-
if (!isViewable
|
|
87
|
-
return /*#__PURE__*/React.createElement(
|
|
88
|
-
|
|
89
|
+
if (!(isViewable || isLoaded || failed) || (itemState === null || itemState === void 0 ? void 0 : itemState.state) === STATE.FAIL || (itemState === null || itemState === void 0 ? void 0 : itemState.state) === STATE.INIT) {
|
|
90
|
+
return /*#__PURE__*/React.createElement(ImageBackground, {
|
|
91
|
+
source: {
|
|
92
|
+
uri: 'https://ssl.pstatic.net/static/m/comic/im/2012/bg_viewbody.jpg'
|
|
93
|
+
},
|
|
94
|
+
resizeMode: "repeat",
|
|
95
|
+
style: viewStyle
|
|
89
96
|
});
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
if (errorCount.current >= errorRetryCount) {
|
|
93
|
-
return /*#__PURE__*/React.createElement(
|
|
100
|
+
return /*#__PURE__*/React.createElement(ImageBackground, {
|
|
101
|
+
source: {
|
|
102
|
+
uri: 'https://ssl.pstatic.net/static/m/comic/im/2012/bg_viewbody.jpg'
|
|
103
|
+
},
|
|
104
|
+
resizeMode: "repeat",
|
|
94
105
|
style: [viewStyle, styles.reload]
|
|
95
106
|
}, /*#__PURE__*/React.createElement(Spacer, {
|
|
96
107
|
size: 20
|
|
@@ -109,24 +120,26 @@ function ViewerItem(_ref) {
|
|
|
109
120
|
}));
|
|
110
121
|
}
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}, children) : null;
|
|
121
|
-
}, [isViewable, isLoaded, errorCount.current, url, onItemPress]);
|
|
123
|
+
return /*#__PURE__*/React.createElement(ImageBackground, {
|
|
124
|
+
source: {
|
|
125
|
+
uri: 'https://ssl.pstatic.net/static/m/comic/im/2012/bg_viewbody.jpg'
|
|
126
|
+
},
|
|
127
|
+
resizeMode: "repeat",
|
|
128
|
+
style: viewStyle
|
|
129
|
+
}, children);
|
|
130
|
+
}, [isViewable, isLoaded, errorCount.current, itemState === null || itemState === void 0 ? void 0 : itemState.state, responseTimestamp]);
|
|
122
131
|
useEffect(() => {
|
|
123
|
-
if (
|
|
132
|
+
if ((itemState === null || itemState === void 0 ? void 0 : itemState.state) === STATE.INIT) {
|
|
124
133
|
getNextPage === null || getNextPage === void 0 ? void 0 : getNextPage(sortKey);
|
|
125
134
|
}
|
|
126
135
|
}, []);
|
|
127
|
-
return /*#__PURE__*/React.createElement(
|
|
128
|
-
|
|
136
|
+
return /*#__PURE__*/React.createElement(TouchableOpacity, {
|
|
137
|
+
activeOpacity: 1,
|
|
138
|
+
onPress: onItemPress
|
|
139
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
140
|
+
style: [styles.root, viewStyle]
|
|
129
141
|
}, /*#__PURE__*/React.createElement(Image, {
|
|
142
|
+
failDependency: [url, expiresAt, responseTimestamp],
|
|
130
143
|
disableOutline: true,
|
|
131
144
|
key: sortKey,
|
|
132
145
|
disableLongClick: true,
|
|
@@ -137,25 +150,42 @@ function ViewerItem(_ref) {
|
|
|
137
150
|
source: {
|
|
138
151
|
uri: url
|
|
139
152
|
},
|
|
140
|
-
style:
|
|
153
|
+
style: imageStyle,
|
|
141
154
|
square: true,
|
|
142
|
-
Placeholder: Placeholder
|
|
143
|
-
|
|
155
|
+
Placeholder: Placeholder,
|
|
156
|
+
disablePlaceholder: true
|
|
157
|
+
})));
|
|
144
158
|
}
|
|
145
159
|
|
|
146
160
|
export default /*#__PURE__*/React.memo(ViewerItem, (prevProps, nextProps) => {
|
|
161
|
+
var _prevProps$props$item, _nextProps$props$item, _prevProps$props$item2;
|
|
162
|
+
|
|
147
163
|
if (prevProps.props.isViewable !== nextProps.props.isViewable) {
|
|
148
164
|
return false;
|
|
149
|
-
}
|
|
165
|
+
} // NO NEED ?
|
|
166
|
+
|
|
150
167
|
|
|
151
168
|
if (prevProps.props.url !== nextProps.props.url) {
|
|
152
169
|
return false;
|
|
170
|
+
} // NO NEED ?
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if (prevProps.props.expiresAt !== nextProps.props.expiresAt) {
|
|
174
|
+
return false;
|
|
153
175
|
}
|
|
154
176
|
|
|
155
177
|
if (prevProps.props.width !== nextProps.props.width) {
|
|
156
178
|
return false;
|
|
157
179
|
}
|
|
158
180
|
|
|
181
|
+
if (((_prevProps$props$item = prevProps.props.itemState) === null || _prevProps$props$item === void 0 ? void 0 : _prevProps$props$item.state) !== ((_nextProps$props$item = nextProps.props.itemState) === null || _nextProps$props$item === void 0 ? void 0 : _nextProps$props$item.state)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (((_prevProps$props$item2 = prevProps.props.itemState) === null || _prevProps$props$item2 === void 0 ? void 0 : _prevProps$props$item2.state) !== STATE.LOADED && prevProps.props.responseTimestamp !== nextProps.props.responseTimestamp) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
159
189
|
return true;
|
|
160
190
|
});
|
|
161
191
|
//# sourceMappingURL=ViewerItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useCallback","useEffect","useRef","useState","Pressable","View","R","IconButton","Image","Spacer","useTheme","Restart","useStyles","theme","root","display","flexDirection","justifyContent","init","backgroundColor","palette","paper","grey","failed","reload","alignItems","ViewerItem","props","expiresAt","errorRetryCount","height","itemState","isViewable","sortKey","url","width","getNextPage","onError","onLoaded","onItemPress","isLoaded","setIsLoaded","styles","errorCount","defaultTo","error","count","onLoad","current","handleError","now","Date","utcNow","getTime","getTimezoneOffset","expired","onReloadPress","viewStyle","Placeholder","children","borderRadius","color","uri","memo","prevProps","nextProps"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { Pressable, View } from 'react-native';\nimport * as R from 'ramda';\nimport type { PlaceholderProps } from '@fountain-ui/core';\nimport { IconButton, Image, Spacer, useTheme } from '@fountain-ui/core';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { Restart } from '@fountain-ui/icons';\nimport ComicViewerItemProps from './ComicViewerItemProps';\n\ntype PlaceholderStyles = NamedStylesStringUnion<'init' | 'failed' | 'reload' | 'root'>;\n\nconst useStyles: UseStyles<PlaceholderStyles> = function (): PlaceholderStyles {\n const theme = useTheme();\n\n return {\n root: {\n display: 'flex',\n flexDirection: 'row',\n justifyContent: 'center',\n },\n init: {\n backgroundColor: theme.palette.paper.grey,\n },\n failed: {\n backgroundColor: theme.palette.paper.grey,\n },\n reload: {\n backgroundColor: theme.palette.paper.grey,\n display: 'flex',\n alignItems: 'center',\n },\n };\n};\n\nfunction ViewerItem<T>({ props }: { props: ComicViewerItemProps<T> }) {\n const {\n expiresAt,\n errorRetryCount = 3,\n height,\n itemState,\n isViewable,\n sortKey,\n url,\n width,\n getNextPage,\n onError,\n onLoaded,\n onItemPress,\n } = props;\n\n const [isLoaded, setIsLoaded] = useState(false);\n\n const styles = useStyles();\n\n const errorCount = useRef<number>(R.defaultTo(0)(itemState?.error?.count));\n\n const onLoad = useCallback(() => {\n errorCount.current = 0;\n\n setIsLoaded(true);\n\n onLoaded && onLoaded(sortKey);\n }, [sortKey]);\n\n const handleError = useCallback(() => {\n errorCount.current = errorCount.current + 1;\n\n const now = new Date();\n const utcNow = now.getTime() + (now.getTimezoneOffset() * 60 * 1000);\n const expired = new Date(expiresAt).getTime() <= utcNow;\n\n onError && onError({\n sortKey,\n count: errorCount.current,\n expired,\n });\n }, [errorCount.current]);\n\n const onReloadPress = useCallback(() => {\n errorCount.current = 1;\n\n onError && onError({\n sortKey,\n count: errorCount.current,\n expired: false,\n });\n }, [sortKey]);\n\n const viewStyle = { width, height };\n\n const Placeholder = useCallback((props: PlaceholderProps) => {\n const { children, failed } = props;\n\n if ((!isViewable && !isLoaded) || url === '') {\n return <View style={[\n viewStyle,\n styles.init,\n ]}/>;\n }\n\n if (errorCount.current >= errorRetryCount) {\n return <View style={[\n viewStyle,\n styles.reload,\n ]}>\n <Spacer size={20}/>\n\n <IconButton\n children={<Restart fill={'#ffffff'}/>}\n style={{\n width: 48,\n height: 48,\n borderRadius: 24,\n color: '#ffffff',\n backgroundColor: '#767676',\n }}\n onPress={onReloadPress}\n />\n </View>;\n }\n\n if (failed) {\n return (\n <View style={[\n viewStyle,\n styles.failed,\n ]}/>\n );\n }\n\n return children ? (\n <Pressable onPress={onItemPress}>\n {children}\n </Pressable>\n ) : null;\n }, [isViewable, isLoaded, errorCount.current, url, onItemPress]);\n\n useEffect(() => {\n if (url === '') {\n getNextPage?.(sortKey);\n }\n }, []);\n\n return (\n <View style={styles.root}>\n <Image\n disableOutline={true}\n key={sortKey}\n disableLongClick={true}\n disableDrag={true}\n onLoad={onLoad}\n onError={handleError}\n loading={'eager'}\n source={{ uri: url }}\n style={viewStyle}\n square={true}\n Placeholder={Placeholder}\n />\n </View>\n );\n}\n\nexport default React.memo(ViewerItem, (prevProps, nextProps) => {\n if (prevProps.props.isViewable !== nextProps.props.isViewable) {\n return false;\n }\n\n if (prevProps.props.url !== nextProps.props.url) {\n return false;\n }\n\n if (prevProps.props.width !== nextProps.props.width) {\n return false;\n }\n\n return true;\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useRef","useState","ImageBackground","Platform","TouchableOpacity","View","R","IconButton","Image","Spacer","Restart","STATE","useStyles","root","display","flexDirection","justifyContent","reload","alignItems","ViewerItem","props","expiresAt","errorRetryCount","height","itemState","isViewable","sortKey","responseTimestamp","url","width","getNextPage","onError","onLoaded","onItemPress","isLoaded","setIsLoaded","styles","errorCount","defaultTo","error","count","onLoad","current","handleError","now","Date","utcNow","getTime","getTimezoneOffset","expired","onReloadPress","viewStyle","select","web","imageStyle","Placeholder","children","failed","state","FAIL","INIT","uri","borderRadius","color","backgroundColor","memo","prevProps","nextProps","LOADED"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { ImageBackground, Platform, TouchableOpacity, View } from 'react-native';\nimport * as R from 'ramda';\nimport type { PlaceholderProps } from '@fountain-ui/core';\nimport { IconButton, Image, Spacer } from '@fountain-ui/core';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { Restart } from '@fountain-ui/icons';\nimport ComicViewerItemProps from './ComicViewerItemProps';\nimport { STATE } from './ComicViewerProps';\n\ntype PlaceholderStyles = NamedStylesStringUnion<'reload' | 'root'>;\n\nconst useStyles: UseStyles<PlaceholderStyles> = function (): PlaceholderStyles {\n return {\n root: {\n display: 'flex',\n flexDirection: 'row',\n justifyContent: 'center',\n },\n reload: {\n display: 'flex',\n alignItems: 'center',\n },\n };\n};\n\nfunction ViewerItem<T>({ props }: { props: ComicViewerItemProps<T> }) {\n const {\n expiresAt,\n errorRetryCount = 3,\n height,\n itemState,\n isViewable,\n sortKey,\n responseTimestamp,\n url,\n width,\n getNextPage,\n onError,\n onLoaded,\n onItemPress,\n } = props;\n\n const [isLoaded, setIsLoaded] = useState(false);\n\n const styles = useStyles();\n\n const errorCount = useRef<number>(R.defaultTo(0)(itemState?.error?.count));\n\n const onLoad = useCallback(() => {\n errorCount.current = 0;\n\n setIsLoaded(true);\n\n onLoaded && onLoaded(sortKey);\n }, [sortKey, onLoaded]);\n\n const handleError = useCallback(() => {\n errorCount.current = errorCount.current + 1;\n\n const now = new Date();\n const utcNow = now.getTime() + (now.getTimezoneOffset() * 60 * 1000);\n const expired = new Date(expiresAt).getTime() <= utcNow;\n\n onError && onError({\n sortKey,\n count: errorCount.current,\n expired,\n });\n }, [errorCount.current, onError]);\n\n const onReloadPress = useCallback(() => {\n errorCount.current = 1;\n\n onError && onError({\n sortKey,\n count: errorCount.current,\n expired: false,\n });\n }, [sortKey, onError]);\n\n const viewStyle = {\n width: '100%',\n height,\n ...Platform.select({\n web: { 'cursor': 'default' },\n }),\n };\n\n const imageStyle = { width, height };\n\n const Placeholder = useCallback((props: PlaceholderProps) => {\n const { children, failed } = props;\n\n if (!(isViewable || isLoaded || failed)\n || (itemState?.state === STATE.FAIL)\n || itemState?.state === STATE.INIT\n ) {\n return <ImageBackground\n source={{ uri: 'https://ssl.pstatic.net/static/m/comic/im/2012/bg_viewbody.jpg' }}\n resizeMode=\"repeat\"\n style={viewStyle}\n />;\n }\n\n if (errorCount.current >= errorRetryCount) {\n return <ImageBackground\n source={{ uri: 'https://ssl.pstatic.net/static/m/comic/im/2012/bg_viewbody.jpg' }}\n resizeMode=\"repeat\"\n style={[\n viewStyle,\n styles.reload,\n ]}\n >\n <Spacer size={20}/>\n\n <IconButton\n children={<Restart fill={'#ffffff'}/>}\n style={{\n width: 48,\n height: 48,\n borderRadius: 24,\n color: '#ffffff',\n backgroundColor: '#767676',\n }}\n onPress={onReloadPress}\n />\n </ImageBackground>;\n }\n\n return <ImageBackground\n source={{ uri: 'https://ssl.pstatic.net/static/m/comic/im/2012/bg_viewbody.jpg' }}\n resizeMode=\"repeat\"\n style={viewStyle}\n >\n {children}\n </ImageBackground>;\n }, [isViewable, isLoaded, errorCount.current, itemState?.state, responseTimestamp]);\n\n useEffect(() => {\n if (itemState?.state === STATE.INIT) {\n getNextPage?.(sortKey);\n }\n }, []);\n\n return (\n <TouchableOpacity\n activeOpacity={1}\n onPress={onItemPress}\n >\n <View\n style={[\n styles.root,\n viewStyle,\n ]}\n >\n <Image\n failDependency={[url, expiresAt, responseTimestamp]}\n disableOutline={true}\n key={sortKey}\n disableLongClick={true}\n disableDrag={true}\n onLoad={onLoad}\n onError={handleError}\n loading={'eager'}\n source={{ uri: url }}\n style={imageStyle}\n square={true}\n Placeholder={Placeholder}\n disablePlaceholder={true}\n />\n </View>\n </TouchableOpacity>\n );\n}\n\nexport default React.memo(ViewerItem, (prevProps, nextProps) => {\n if (prevProps.props.isViewable !== nextProps.props.isViewable) {\n return false;\n }\n\n // NO NEED ?\n if (prevProps.props.url !== nextProps.props.url) {\n return false;\n }\n\n // NO NEED ?\n if (prevProps.props.expiresAt !== nextProps.props.expiresAt) {\n return false;\n }\n\n if (prevProps.props.width !== nextProps.props.width) {\n return false;\n }\n\n if (prevProps.props.itemState?.state !== nextProps.props.itemState?.state) {\n return false;\n }\n\n if (prevProps.props.itemState?.state !== STATE.LOADED && prevProps.props.responseTimestamp !== nextProps.props.responseTimestamp) {\n return false;\n }\n\n return true;\n});"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { ComponentProps } from '@fountain-ui/core';
|
|
3
3
|
import { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
|
|
4
4
|
export declare const STATE: {
|
|
5
|
-
readonly
|
|
6
|
-
readonly
|
|
5
|
+
readonly INIT: "init";
|
|
6
|
+
readonly URL_LOADED: "url_loaded";
|
|
7
7
|
readonly LOADED: "loaded";
|
|
8
8
|
readonly FAIL: "fail";
|
|
9
9
|
};
|
|
@@ -61,6 +61,10 @@ export declare type ComicViewerItemData<T = {}> = T & {
|
|
|
61
61
|
* Image expire date.
|
|
62
62
|
*/
|
|
63
63
|
expiresAt: string;
|
|
64
|
+
/***
|
|
65
|
+
* Timestamp when get content response
|
|
66
|
+
*/
|
|
67
|
+
responseTimestamp: number;
|
|
64
68
|
};
|
|
65
69
|
export default interface ComicViewerProps<T> extends ComponentProps<{
|
|
66
70
|
/**
|
|
@@ -93,6 +97,10 @@ export default interface ComicViewerProps<T> extends ComponentProps<{
|
|
|
93
97
|
* @default 0
|
|
94
98
|
*/
|
|
95
99
|
itemVisiblePercentThreshold?: number;
|
|
100
|
+
/***
|
|
101
|
+
* Timestamp when get content response
|
|
102
|
+
*/
|
|
103
|
+
responseTimestamp: number;
|
|
96
104
|
/**
|
|
97
105
|
* Comic viewer width.
|
|
98
106
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fountain-ui/lab",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.34",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Fountain-UI Team",
|
|
6
6
|
"description": "Incubator for Fountain-UI React components.",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "44aa49c39c8a9f0986b9d12e06a8a2cfc3766ed9"
|
|
74
74
|
}
|
|
@@ -22,6 +22,7 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
22
22
|
data,
|
|
23
23
|
errorDebounceMillis = 500,
|
|
24
24
|
errorRetryCount = 3,
|
|
25
|
+
responseTimestamp,
|
|
25
26
|
initialNumToRender = 1,
|
|
26
27
|
initialScrollPercentage = 0,
|
|
27
28
|
itemVisiblePercentThreshold = 0,
|
|
@@ -42,8 +43,6 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
42
43
|
|
|
43
44
|
const debounceTimeOut = useRef<NodeJS.Timeout | null>(null);
|
|
44
45
|
|
|
45
|
-
const resourceString = R.toString(R.map((itemData: ComicViewerItemData) => itemData.url)(data));
|
|
46
|
-
|
|
47
46
|
const imageWidth = Math.min(viewerWidth, 720);
|
|
48
47
|
const initialItems = R.map((itemData: ComicViewerItemData<T>) => ({
|
|
49
48
|
...itemData,
|
|
@@ -56,7 +55,7 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
56
55
|
|
|
57
56
|
const initialItemState: ComicViewerItemState[] = R.map((itemData: ComicViewerItemData<T>) => ({
|
|
58
57
|
sortKey: itemData.sortKey,
|
|
59
|
-
state: STATE.
|
|
58
|
+
state: R.isNil(itemData.id) ? STATE.INIT : STATE.URL_LOADED,
|
|
60
59
|
}))(data);
|
|
61
60
|
|
|
62
61
|
const itemStates = useRef<Array<ComicViewerItemState>>(initialItemState);
|
|
@@ -82,11 +81,27 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
82
81
|
viewableItems: Array<ViewToken>,
|
|
83
82
|
}) => {
|
|
84
83
|
setItems((prev: ComicViewerItemProps<T>[]) => {
|
|
85
|
-
const viewableItemSortKeys = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);
|
|
86
|
-
|
|
84
|
+
const viewableItemSortKeys: number[] = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);
|
|
85
|
+
const firstViewableSortKey = R.head(viewableItemSortKeys);
|
|
86
|
+
const lastViewableItemSortKey = R.last(viewableItemSortKeys);
|
|
87
|
+
const firstItem = R.head(prev);
|
|
88
|
+
const lastItem = R.last(prev);
|
|
89
|
+
|
|
90
|
+
if (R.isNil(firstViewableSortKey)
|
|
91
|
+
|| R.isNil(lastViewableItemSortKey)
|
|
92
|
+
|| R.isNil(firstItem)
|
|
93
|
+
|| R.isNil(lastItem)
|
|
94
|
+
) {
|
|
95
|
+
return prev;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const frontBoundary = R.max(firstItem.sortKey, firstViewableSortKey - 1);
|
|
99
|
+
const backBoundary = R.min(lastItem.sortKey, lastViewableItemSortKey + 1);
|
|
100
|
+
|
|
101
|
+
const viewableItemBoundary = R.range(frontBoundary, backBoundary + 1);
|
|
87
102
|
const newItems = R.map((prevItem: ComicViewerItemProps<T>) => ({
|
|
88
103
|
...prevItem,
|
|
89
|
-
isViewable: R.includes(prevItem.sortKey,
|
|
104
|
+
isViewable: R.includes(prevItem.sortKey, viewableItemBoundary),
|
|
90
105
|
}))([...prev]);
|
|
91
106
|
|
|
92
107
|
return newItems;
|
|
@@ -147,6 +162,7 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
147
162
|
const props = {
|
|
148
163
|
...item,
|
|
149
164
|
itemState,
|
|
165
|
+
responseTimestamp,
|
|
150
166
|
errorRetryCount,
|
|
151
167
|
onError: itemErrorHandler,
|
|
152
168
|
onLoaded: itemLoadedHandler,
|
|
@@ -155,7 +171,7 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
155
171
|
};
|
|
156
172
|
|
|
157
173
|
return <ViewerItem props={props}/>;
|
|
158
|
-
}, [
|
|
174
|
+
}, [responseTimestamp, itemErrorHandler, itemLoadedHandler, onItemPress]);
|
|
159
175
|
|
|
160
176
|
useEffect(() => {
|
|
161
177
|
setItems((prev: ComicViewerItemProps<T>[]) => {
|
|
@@ -164,9 +180,12 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
164
180
|
const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === currentData?.sortKey)(itemStates.current);
|
|
165
181
|
|
|
166
182
|
if (currentData
|
|
183
|
+
&& currentData.id
|
|
167
184
|
&& itemState
|
|
168
|
-
&& itemState.state !== STATE.LOADED
|
|
169
|
-
|
|
185
|
+
&& itemState.state !== STATE.LOADED) {
|
|
186
|
+
|
|
187
|
+
itemState.state = STATE.URL_LOADED;
|
|
188
|
+
|
|
170
189
|
return {
|
|
171
190
|
...prevItem,
|
|
172
191
|
url: currentData.url,
|
|
@@ -178,7 +197,7 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
178
197
|
})([...prev]);
|
|
179
198
|
;
|
|
180
199
|
});
|
|
181
|
-
}, [
|
|
200
|
+
}, [responseTimestamp]);
|
|
182
201
|
|
|
183
202
|
useEffect(() => {
|
|
184
203
|
const newItems = R.map((item: ComicViewerItemProps<T>) => ({
|
|
@@ -215,4 +234,4 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
215
234
|
{...otherProps}
|
|
216
235
|
/>
|
|
217
236
|
);
|
|
218
|
-
};
|
|
237
|
+
};
|
|
@@ -3,8 +3,8 @@ import { ComponentProps } from '@fountain-ui/core';
|
|
|
3
3
|
import { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
|
|
4
4
|
|
|
5
5
|
export const STATE = {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
INIT: 'init',
|
|
7
|
+
URL_LOADED: 'url_loaded',
|
|
8
8
|
LOADED: 'loaded',
|
|
9
9
|
FAIL: 'fail',
|
|
10
10
|
} as const;
|
|
@@ -75,6 +75,11 @@ export type ComicViewerItemData<T = {}> = T & {
|
|
|
75
75
|
* Image expire date.
|
|
76
76
|
*/
|
|
77
77
|
expiresAt: string;
|
|
78
|
+
|
|
79
|
+
/***
|
|
80
|
+
* Timestamp when get content response
|
|
81
|
+
*/
|
|
82
|
+
responseTimestamp: number;
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
export default interface ComicViewerProps<T> extends ComponentProps <{
|
|
@@ -114,6 +119,11 @@ export default interface ComicViewerProps<T> extends ComponentProps <{
|
|
|
114
119
|
*/
|
|
115
120
|
itemVisiblePercentThreshold?: number;
|
|
116
121
|
|
|
122
|
+
/***
|
|
123
|
+
* Timestamp when get content response
|
|
124
|
+
*/
|
|
125
|
+
responseTimestamp: number;
|
|
126
|
+
|
|
117
127
|
/**
|
|
118
128
|
* Comic viewer width.
|
|
119
129
|
*/
|