@fountain-ui/lab 2.0.0-beta.32 → 2.0.0-beta.33
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 +15 -2
- 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 +27 -15
- package/build/commonjs/ComicViewer/ViewerItem.js.map +1 -1
- package/build/module/ComicViewer/ComicViewer.js +15 -2
- 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 +27 -16
- package/build/module/ComicViewer/ViewerItem.js.map +1 -1
- package/build/typescript/ComicViewer/ComicViewerProps.d.ts +2 -2
- package/package.json +2 -2
- package/src/ComicViewer/ComicViewer.tsx +25 -6
- package/src/ComicViewer/ComicViewerProps.ts +2 -2
- package/src/ComicViewer/ViewerItem.tsx +46 -33
|
@@ -62,7 +62,7 @@ function ComicViewer(props) {
|
|
|
62
62
|
const [items, setItems] = (0, _react.useState)(initialItems);
|
|
63
63
|
const initialItemState = R.map(itemData => ({
|
|
64
64
|
sortKey: itemData.sortKey,
|
|
65
|
-
state: _ComicViewerProps.STATE.
|
|
65
|
+
state: R.isEmpty(itemData.expiresAt) ? _ComicViewerProps.STATE.INIT : _ComicViewerProps.STATE.URL_LOADED
|
|
66
66
|
}))(data);
|
|
67
67
|
const itemStates = (0, _react.useRef)(initialItemState);
|
|
68
68
|
const itemHeights = [...getItemHeights(items)];
|
|
@@ -84,8 +84,20 @@ function ComicViewer(props) {
|
|
|
84
84
|
} = _ref;
|
|
85
85
|
setItems(prev => {
|
|
86
86
|
const viewableItemSortKeys = R.map(viewableItem => viewableItem.item.sortKey)(viewableItems);
|
|
87
|
+
const firstViewableSortKey = R.head(viewableItemSortKeys);
|
|
88
|
+
const lastViewableItemSortKey = R.last(viewableItemSortKeys);
|
|
89
|
+
const firstItem = R.head(prev);
|
|
90
|
+
const lastItem = R.last(prev);
|
|
91
|
+
|
|
92
|
+
if (R.isNil(firstViewableSortKey) || R.isNil(lastViewableItemSortKey) || R.isNil(firstItem) || R.isNil(lastItem)) {
|
|
93
|
+
return prev;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const frontBoundary = R.max(firstItem.sortKey, firstViewableSortKey - 1);
|
|
97
|
+
const backBoundary = R.min(lastItem.sortKey, lastViewableItemSortKey + 1);
|
|
98
|
+
const viewableItemBoundary = R.range(frontBoundary, backBoundary + 1);
|
|
87
99
|
const newItems = R.map(prevItem => ({ ...prevItem,
|
|
88
|
-
isViewable: R.includes(prevItem.sortKey,
|
|
100
|
+
isViewable: R.includes(prevItem.sortKey, viewableItemBoundary)
|
|
89
101
|
}))([...prev]);
|
|
90
102
|
return newItems;
|
|
91
103
|
});
|
|
@@ -164,6 +176,7 @@ function ComicViewer(props) {
|
|
|
164
176
|
const itemState = R.find(state => state.sortKey === (currentData === null || currentData === void 0 ? void 0 : currentData.sortKey))(itemStates.current);
|
|
165
177
|
|
|
166
178
|
if (currentData && itemState && itemState.state !== _ComicViewerProps.STATE.LOADED && currentData.url !== prevItem.url) {
|
|
179
|
+
itemState.state = _ComicViewerProps.STATE.URL_LOADED;
|
|
167
180
|
return { ...prevItem,
|
|
168
181
|
url: currentData.url,
|
|
169
182
|
expiresAt: currentData.expiresAt
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["getItemHeights","items","R","map","content","height","appender","left","right","getHeightAccum","itemHeights","mapAccum","keyExtractor","item","sortKey","ComicViewer","props","data","errorDebounceMillis","errorRetryCount","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","onError","onScroll","onItemPress","getNextPage","viewerWidth","windowSize","pageUnit","ListFooterComponent","otherProps","flatListRef","useRef","errors","Map","debounceTimeOut","resourceString","toString","itemData","url","imageWidth","Math","min","initialItems","isViewable","width","setItems","useState","initialItemState","state","STATE","UNLOAD","itemStates","itemHeightAccum","viewabilityConfig","useMemo","getItemLayout","useCallback","index","offsets","prepend","length","offset","onViewableItemsChanged","viewableItems","prev","viewableItemSortKeys","viewableItem","newItems","prevItem","includes","itemLoadedHandler","itemState","find","current","isNil","LOADED","error","undefined","itemErrorHandler","errorInfo","count","set","FAIL","handleError","errorsArray","Array","from","entries","errorsInfo","key","value","clear","clearTimeout","size","setTimeout","renderItem","onLoaded","useEffect","currentData","currentItemData","expiresAt","totalHeight","floor","scrollToOffset","animated"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport {\n ComicViewerItemData,\n ComicViewerItemState,\n default as ComicViewerProps,\n ErrorInfo,\n STATE,\n} from './ComicViewerProps';\nimport type ComicViewerItemProps from './ComicViewerItemProps';\nimport ViewerItem from './ViewerItem';\n\nconst getItemHeights = <T, >(items: ComicViewerItemProps<T>[]): number[] => R.map((content: ComicViewerItemProps<T>) => content.height)(items);\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (itemHeights: number[]): [number, number[]] => R.mapAccum(appender, 0, itemHeights);\n\nconst keyExtractor = <T, >(item: ComicViewerItemProps<T>) => `${item.sortKey}`;\n\nexport default function ComicViewer<T>(props: ComicViewerProps<T>) {\n const {\n data,\n errorDebounceMillis = 500,\n errorRetryCount = 3,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n onError,\n onScroll,\n onItemPress,\n getNextPage,\n viewerWidth,\n windowSize = 3,\n pageUnit,\n ListFooterComponent,\n ...otherProps\n } = props;\n\n const flatListRef = useRef<FlatList>(null);\n\n const errors = useRef<Map<number, ErrorInfo>>(new Map());\n\n const debounceTimeOut = useRef<NodeJS.Timeout | null>(null);\n\n const resourceString = R.toString(R.map((itemData: ComicViewerItemData) => itemData.url)(data));\n\n const imageWidth = Math.min(viewerWidth, 720);\n const initialItems = R.map((itemData: ComicViewerItemData<T>) => ({\n ...itemData,\n isViewable: false,\n width: imageWidth,\n height: (itemData.height * imageWidth) / itemData.width,\n }))(data);\n\n const [items, setItems] = useState<ComicViewerItemProps<T>[]>(initialItems);\n\n const initialItemState: ComicViewerItemState[] = R.map((itemData: ComicViewerItemData<T>) => ({\n sortKey: itemData.sortKey,\n state: STATE.UNLOAD,\n }))(data);\n\n const itemStates = useRef<Array<ComicViewerItemState>>(initialItemState);\n\n const itemHeights = [...getItemHeights(items)];\n const itemHeightAccum = getHeightAccum(itemHeights);\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const getItemLayout = useCallback((data: any, index: number) => {\n const offsets = R.prepend(0, itemHeightAccum[1]);\n\n return {\n length: itemHeights[index],\n offset: offsets[index],\n index,\n };\n }, [itemHeights]);\n\n const onViewableItemsChanged = useRef(({ viewableItems }: {\n viewableItems: Array<ViewToken>,\n }) => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n const viewableItemSortKeys = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);\n\n const newItems = R.map((prevItem: ComicViewerItemProps<T>) => ({\n ...prevItem,\n isViewable: R.includes(prevItem.sortKey, viewableItemSortKeys),\n }))([...prev]);\n\n return newItems;\n });\n });\n\n const itemLoadedHandler = useCallback((sortKey: number) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.LOADED;\n itemState.error = undefined;\n }, [itemStates]);\n\n const itemErrorHandler = useCallback((errorInfo: ErrorInfo) => {\n const { sortKey, count } = errorInfo;\n\n if (count >= errorRetryCount) {\n return;\n }\n\n errors.current.set(sortKey, errorInfo);\n\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.FAIL;\n itemState.error = errorInfo;\n\n const handleError = () => {\n const errorsArray = Array.from(errors.current.entries());\n const errorsInfo = R.map(([key, value]: [number, ErrorInfo]) => value)(errorsArray);\n\n onError && onError([...errorsInfo]);\n errors.current.clear();\n };\n\n if (debounceTimeOut.current) {\n clearTimeout(debounceTimeOut.current);\n }\n\n if (errors.current.size === pageUnit) {\n handleError();\n } else {\n debounceTimeOut.current = setTimeout(handleError, errorDebounceMillis);\n }\n }, [errors.current, itemStates]);\n\n const renderItem: ListRenderItem<ComicViewerItemProps<T>> = useCallback(({ item }) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === item.sortKey)(itemStates.current);\n\n const props = {\n ...item,\n itemState,\n errorRetryCount,\n onError: itemErrorHandler,\n onLoaded: itemLoadedHandler,\n onItemPress,\n getNextPage,\n };\n\n return <ViewerItem props={props}/>;\n }, [resourceString, itemErrorHandler, itemLoadedHandler, onItemPress]);\n\n useEffect(() => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n return R.map((prevItem: ComicViewerItemProps<T>) => {\n const currentData: ComicViewerItemData | undefined = R.find((currentItemData: ComicViewerItemData<T>) => prevItem.sortKey === currentItemData.sortKey)(data);\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === currentData?.sortKey)(itemStates.current);\n\n if (currentData\n && itemState\n && itemState.state !== STATE.LOADED\n && (currentData.url !== prevItem.url)) {\n return {\n ...prevItem,\n url: currentData.url,\n expiresAt: currentData.expiresAt,\n };\n }\n\n return prevItem;\n })([...prev]);\n ;\n });\n }, [resourceString]);\n\n useEffect(() => {\n const newItems = R.map((item: ComicViewerItemProps<T>) => ({\n ...item,\n width: imageWidth,\n height: (item.height * imageWidth) / item.width,\n }))(items);\n\n setItems(newItems);\n }, [imageWidth]);\n\n useEffect(() => {\n const totalHeight = itemHeightAccum[0];\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, [flatListRef.current]);\n\n return (\n <FlatList\n data={items}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n onScroll={onScroll}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n ListFooterComponent={ListFooterComponent}\n {...otherProps}\n />\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["getItemHeights","items","R","map","content","height","appender","left","right","getHeightAccum","itemHeights","mapAccum","keyExtractor","item","sortKey","ComicViewer","props","data","errorDebounceMillis","errorRetryCount","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","onError","onScroll","onItemPress","getNextPage","viewerWidth","windowSize","pageUnit","ListFooterComponent","otherProps","flatListRef","useRef","errors","Map","debounceTimeOut","resourceString","toString","itemData","url","imageWidth","Math","min","initialItems","isViewable","width","setItems","useState","initialItemState","state","isEmpty","expiresAt","STATE","INIT","URL_LOADED","itemStates","itemHeightAccum","viewabilityConfig","useMemo","getItemLayout","useCallback","index","offsets","prepend","length","offset","onViewableItemsChanged","viewableItems","prev","viewableItemSortKeys","viewableItem","firstViewableSortKey","head","lastViewableItemSortKey","last","firstItem","lastItem","isNil","frontBoundary","max","backBoundary","viewableItemBoundary","range","newItems","prevItem","includes","itemLoadedHandler","itemState","find","current","LOADED","error","undefined","itemErrorHandler","errorInfo","count","set","FAIL","handleError","errorsArray","Array","from","entries","errorsInfo","key","value","clear","clearTimeout","size","setTimeout","renderItem","onLoaded","useEffect","currentData","currentItemData","totalHeight","floor","scrollToOffset","animated"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport {\n ComicViewerItemData,\n ComicViewerItemState,\n default as ComicViewerProps,\n ErrorInfo,\n STATE,\n} from './ComicViewerProps';\nimport type ComicViewerItemProps from './ComicViewerItemProps';\nimport ViewerItem from './ViewerItem';\n\nconst getItemHeights = <T, >(items: ComicViewerItemProps<T>[]): number[] => R.map((content: ComicViewerItemProps<T>) => content.height)(items);\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (itemHeights: number[]): [number, number[]] => R.mapAccum(appender, 0, itemHeights);\n\nconst keyExtractor = <T, >(item: ComicViewerItemProps<T>) => `${item.sortKey}`;\n\nexport default function ComicViewer<T>(props: ComicViewerProps<T>) {\n const {\n data,\n errorDebounceMillis = 500,\n errorRetryCount = 3,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n onError,\n onScroll,\n onItemPress,\n getNextPage,\n viewerWidth,\n windowSize = 3,\n pageUnit,\n ListFooterComponent,\n ...otherProps\n } = props;\n\n const flatListRef = useRef<FlatList>(null);\n\n const errors = useRef<Map<number, ErrorInfo>>(new Map());\n\n const debounceTimeOut = useRef<NodeJS.Timeout | null>(null);\n\n const resourceString = R.toString(R.map((itemData: ComicViewerItemData) => itemData.url)(data));\n\n const imageWidth = Math.min(viewerWidth, 720);\n const initialItems = R.map((itemData: ComicViewerItemData<T>) => ({\n ...itemData,\n isViewable: false,\n width: imageWidth,\n height: (itemData.height * imageWidth) / itemData.width,\n }))(data);\n\n const [items, setItems] = useState<ComicViewerItemProps<T>[]>(initialItems);\n\n const initialItemState: ComicViewerItemState[] = R.map((itemData: ComicViewerItemData<T>) => ({\n sortKey: itemData.sortKey,\n state: R.isEmpty(itemData.expiresAt) ? STATE.INIT : STATE.URL_LOADED,\n }))(data);\n\n const itemStates = useRef<Array<ComicViewerItemState>>(initialItemState);\n\n const itemHeights = [...getItemHeights(items)];\n const itemHeightAccum = getHeightAccum(itemHeights);\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const getItemLayout = useCallback((data: any, index: number) => {\n const offsets = R.prepend(0, itemHeightAccum[1]);\n\n return {\n length: itemHeights[index],\n offset: offsets[index],\n index,\n };\n }, [itemHeights]);\n\n const onViewableItemsChanged = useRef(({ viewableItems }: {\n viewableItems: Array<ViewToken>,\n }) => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n const viewableItemSortKeys: number[] = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);\n const firstViewableSortKey = R.head(viewableItemSortKeys);\n const lastViewableItemSortKey = R.last(viewableItemSortKeys);\n const firstItem = R.head(prev);\n const lastItem = R.last(prev);\n\n if (R.isNil(firstViewableSortKey)\n || R.isNil(lastViewableItemSortKey)\n || R.isNil(firstItem)\n || R.isNil(lastItem)\n ) {\n return prev;\n }\n\n const frontBoundary = R.max(firstItem.sortKey, firstViewableSortKey - 1);\n const backBoundary = R.min(lastItem.sortKey, lastViewableItemSortKey + 1);\n\n const viewableItemBoundary = R.range(frontBoundary, backBoundary + 1);\n const newItems = R.map((prevItem: ComicViewerItemProps<T>) => ({\n ...prevItem,\n isViewable: R.includes(prevItem.sortKey, viewableItemBoundary),\n }))([...prev]);\n\n return newItems;\n });\n });\n\n const itemLoadedHandler = useCallback((sortKey: number) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.LOADED;\n itemState.error = undefined;\n }, [itemStates]);\n\n const itemErrorHandler = useCallback((errorInfo: ErrorInfo) => {\n const { sortKey, count } = errorInfo;\n\n if (count >= errorRetryCount) {\n return;\n }\n\n errors.current.set(sortKey, errorInfo);\n\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.FAIL;\n itemState.error = errorInfo;\n\n const handleError = () => {\n const errorsArray = Array.from(errors.current.entries());\n const errorsInfo = R.map(([key, value]: [number, ErrorInfo]) => value)(errorsArray);\n\n onError && onError([...errorsInfo]);\n errors.current.clear();\n };\n\n if (debounceTimeOut.current) {\n clearTimeout(debounceTimeOut.current);\n }\n\n if (errors.current.size === pageUnit) {\n handleError();\n } else {\n debounceTimeOut.current = setTimeout(handleError, errorDebounceMillis);\n }\n }, [errors.current, itemStates]);\n\n const renderItem: ListRenderItem<ComicViewerItemProps<T>> = useCallback(({ item }) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === item.sortKey)(itemStates.current);\n\n const props = {\n ...item,\n itemState,\n errorRetryCount,\n onError: itemErrorHandler,\n onLoaded: itemLoadedHandler,\n onItemPress,\n getNextPage,\n };\n\n return <ViewerItem props={props}/>;\n }, [resourceString, itemErrorHandler, itemLoadedHandler, onItemPress]);\n\n useEffect(() => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n return R.map((prevItem: ComicViewerItemProps<T>) => {\n const currentData: ComicViewerItemData | undefined = R.find((currentItemData: ComicViewerItemData<T>) => prevItem.sortKey === currentItemData.sortKey)(data);\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === currentData?.sortKey)(itemStates.current);\n\n if (currentData\n && itemState\n && itemState.state !== STATE.LOADED\n && (currentData.url !== prevItem.url)) {\n\n itemState.state = STATE.URL_LOADED;\n\n return {\n ...prevItem,\n url: currentData.url,\n expiresAt: currentData.expiresAt,\n };\n }\n\n return prevItem;\n })([...prev]);\n ;\n });\n }, [resourceString]);\n\n useEffect(() => {\n const newItems = R.map((item: ComicViewerItemProps<T>) => ({\n ...item,\n width: imageWidth,\n height: (item.height * imageWidth) / item.width,\n }))(items);\n\n setItems(newItems);\n }, [imageWidth]);\n\n useEffect(() => {\n const totalHeight = itemHeightAccum[0];\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, [flatListRef.current]);\n\n return (\n <FlatList\n data={items}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n onScroll={onScroll}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n ListFooterComponent={ListFooterComponent}\n {...otherProps}\n />\n );\n};\n"],"mappings":"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"}
|
|
@@ -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\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 * 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":";;;;;;AAIO,MAAMA,KAAK,GAAG;EACjBC,IAAI,EAAE,MADW;EAEjBC,UAAU,EAAE,YAFK;EAGjBC,MAAM,EAAE,QAHS;EAIjBC,IAAI,EAAE;AAJW,CAAd"}
|
|
@@ -15,6 +15,8 @@ var _core = require("@fountain-ui/core");
|
|
|
15
15
|
|
|
16
16
|
var _icons = require("@fountain-ui/icons");
|
|
17
17
|
|
|
18
|
+
var _ComicViewerProps = require("./ComicViewerProps");
|
|
19
|
+
|
|
18
20
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
21
|
|
|
20
22
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
@@ -89,6 +91,15 @@ function ViewerItem(_ref) {
|
|
|
89
91
|
});
|
|
90
92
|
}, [sortKey]);
|
|
91
93
|
const viewStyle = {
|
|
94
|
+
width: '100%',
|
|
95
|
+
height,
|
|
96
|
+
..._reactNative.Platform.select({
|
|
97
|
+
web: {
|
|
98
|
+
'cursor': 'default'
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
};
|
|
102
|
+
const imageStyle = {
|
|
92
103
|
width,
|
|
93
104
|
height
|
|
94
105
|
};
|
|
@@ -98,7 +109,7 @@ function ViewerItem(_ref) {
|
|
|
98
109
|
failed
|
|
99
110
|
} = props;
|
|
100
111
|
|
|
101
|
-
if (!isViewable
|
|
112
|
+
if (!(isViewable || isLoaded) || failed || (itemState === null || itemState === void 0 ? void 0 : itemState.state) === _ComicViewerProps.STATE.INIT) {
|
|
102
113
|
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
103
114
|
style: [viewStyle, styles.init]
|
|
104
115
|
});
|
|
@@ -124,23 +135,18 @@ function ViewerItem(_ref) {
|
|
|
124
135
|
}));
|
|
125
136
|
}
|
|
126
137
|
|
|
127
|
-
|
|
128
|
-
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
129
|
-
style: [viewStyle, styles.failed]
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return children ? /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
|
|
134
|
-
onPress: onItemPress
|
|
135
|
-
}, children) : null;
|
|
138
|
+
return children;
|
|
136
139
|
}, [isViewable, isLoaded, errorCount.current, url, onItemPress]);
|
|
137
140
|
(0, _react.useEffect)(() => {
|
|
138
|
-
if (
|
|
141
|
+
if ((itemState === null || itemState === void 0 ? void 0 : itemState.state) === _ComicViewerProps.STATE.INIT) {
|
|
139
142
|
getNextPage === null || getNextPage === void 0 ? void 0 : getNextPage(sortKey);
|
|
140
143
|
}
|
|
141
144
|
}, []);
|
|
142
|
-
return /*#__PURE__*/_react.default.createElement(_reactNative.
|
|
143
|
-
|
|
145
|
+
return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
146
|
+
activeOpacity: 1,
|
|
147
|
+
onPress: onItemPress
|
|
148
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
149
|
+
style: [styles.root, viewStyle]
|
|
144
150
|
}, /*#__PURE__*/_react.default.createElement(_core.Image, {
|
|
145
151
|
disableOutline: true,
|
|
146
152
|
key: sortKey,
|
|
@@ -152,13 +158,15 @@ function ViewerItem(_ref) {
|
|
|
152
158
|
source: {
|
|
153
159
|
uri: url
|
|
154
160
|
},
|
|
155
|
-
style:
|
|
161
|
+
style: imageStyle,
|
|
156
162
|
square: true,
|
|
157
163
|
Placeholder: Placeholder
|
|
158
|
-
}));
|
|
164
|
+
})));
|
|
159
165
|
}
|
|
160
166
|
|
|
161
167
|
var _default = /*#__PURE__*/_react.default.memo(ViewerItem, (prevProps, nextProps) => {
|
|
168
|
+
var _prevProps$props$item, _nextProps$props$item;
|
|
169
|
+
|
|
162
170
|
if (prevProps.props.isViewable !== nextProps.props.isViewable) {
|
|
163
171
|
return false;
|
|
164
172
|
}
|
|
@@ -171,6 +179,10 @@ var _default = /*#__PURE__*/_react.default.memo(ViewerItem, (prevProps, nextProp
|
|
|
171
179
|
return false;
|
|
172
180
|
}
|
|
173
181
|
|
|
182
|
+
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)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
174
186
|
return true;
|
|
175
187
|
});
|
|
176
188
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useStyles","theme","useTheme","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","useState","styles","errorCount","useRef","R","defaultTo","error","count","onLoad","useCallback","current","handleError","now","Date","utcNow","getTime","getTimezoneOffset","expired","onReloadPress","viewStyle","Placeholder","children","borderRadius","color","useEffect","uri","React","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":["useStyles","theme","useTheme","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","useState","styles","errorCount","useRef","R","defaultTo","error","count","onLoad","useCallback","current","handleError","now","Date","utcNow","getTime","getTimezoneOffset","expired","onReloadPress","viewStyle","Platform","select","web","imageStyle","Placeholder","children","state","STATE","INIT","borderRadius","color","useEffect","uri","React","memo","prevProps","nextProps"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform, TouchableOpacity, 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';\nimport { STATE } from './ComicViewerProps';\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 = {\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)\n || failed\n || itemState?.state === STATE.INIT\n ) {\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 return children;\n }, [isViewable, isLoaded, errorCount.current, url, onItemPress]);\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 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 />\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 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 if (prevProps.props.itemState?.state !== nextProps.props.itemState?.state) {\n return false;\n }\n\n return true;\n});\n"],"mappings":"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"}
|
|
@@ -45,7 +45,7 @@ export default function ComicViewer(props) {
|
|
|
45
45
|
const [items, setItems] = useState(initialItems);
|
|
46
46
|
const initialItemState = R.map(itemData => ({
|
|
47
47
|
sortKey: itemData.sortKey,
|
|
48
|
-
state: STATE.
|
|
48
|
+
state: R.isEmpty(itemData.expiresAt) ? STATE.INIT : STATE.URL_LOADED
|
|
49
49
|
}))(data);
|
|
50
50
|
const itemStates = useRef(initialItemState);
|
|
51
51
|
const itemHeights = [...getItemHeights(items)];
|
|
@@ -67,8 +67,20 @@ export default function ComicViewer(props) {
|
|
|
67
67
|
} = _ref;
|
|
68
68
|
setItems(prev => {
|
|
69
69
|
const viewableItemSortKeys = R.map(viewableItem => viewableItem.item.sortKey)(viewableItems);
|
|
70
|
+
const firstViewableSortKey = R.head(viewableItemSortKeys);
|
|
71
|
+
const lastViewableItemSortKey = R.last(viewableItemSortKeys);
|
|
72
|
+
const firstItem = R.head(prev);
|
|
73
|
+
const lastItem = R.last(prev);
|
|
74
|
+
|
|
75
|
+
if (R.isNil(firstViewableSortKey) || R.isNil(lastViewableItemSortKey) || R.isNil(firstItem) || R.isNil(lastItem)) {
|
|
76
|
+
return prev;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const frontBoundary = R.max(firstItem.sortKey, firstViewableSortKey - 1);
|
|
80
|
+
const backBoundary = R.min(lastItem.sortKey, lastViewableItemSortKey + 1);
|
|
81
|
+
const viewableItemBoundary = R.range(frontBoundary, backBoundary + 1);
|
|
70
82
|
const newItems = R.map(prevItem => ({ ...prevItem,
|
|
71
|
-
isViewable: R.includes(prevItem.sortKey,
|
|
83
|
+
isViewable: R.includes(prevItem.sortKey, viewableItemBoundary)
|
|
72
84
|
}))([...prev]);
|
|
73
85
|
return newItems;
|
|
74
86
|
});
|
|
@@ -147,6 +159,7 @@ export default function ComicViewer(props) {
|
|
|
147
159
|
const itemState = R.find(state => state.sortKey === (currentData === null || currentData === void 0 ? void 0 : currentData.sortKey))(itemStates.current);
|
|
148
160
|
|
|
149
161
|
if (currentData && itemState && itemState.state !== STATE.LOADED && currentData.url !== prevItem.url) {
|
|
162
|
+
itemState.state = STATE.URL_LOADED;
|
|
150
163
|
return { ...prevItem,
|
|
151
164
|
url: currentData.url,
|
|
152
165
|
expiresAt: currentData.expiresAt
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","FlatList","R","STATE","ViewerItem","getItemHeights","items","map","content","height","appender","left","right","getHeightAccum","itemHeights","mapAccum","keyExtractor","item","sortKey","ComicViewer","props","data","errorDebounceMillis","errorRetryCount","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","onError","onScroll","onItemPress","getNextPage","viewerWidth","windowSize","pageUnit","ListFooterComponent","otherProps","flatListRef","errors","Map","debounceTimeOut","resourceString","toString","itemData","url","imageWidth","Math","min","initialItems","isViewable","width","setItems","initialItemState","state","UNLOAD","itemStates","itemHeightAccum","viewabilityConfig","getItemLayout","index","offsets","prepend","length","offset","onViewableItemsChanged","viewableItems","prev","viewableItemSortKeys","viewableItem","newItems","prevItem","includes","itemLoadedHandler","itemState","find","current","isNil","LOADED","error","undefined","itemErrorHandler","errorInfo","count","set","FAIL","handleError","errorsArray","Array","from","entries","errorsInfo","key","value","clear","clearTimeout","size","setTimeout","renderItem","onLoaded","currentData","currentItemData","expiresAt","totalHeight","floor","scrollToOffset","animated"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport {\n ComicViewerItemData,\n ComicViewerItemState,\n default as ComicViewerProps,\n ErrorInfo,\n STATE,\n} from './ComicViewerProps';\nimport type ComicViewerItemProps from './ComicViewerItemProps';\nimport ViewerItem from './ViewerItem';\n\nconst getItemHeights = <T, >(items: ComicViewerItemProps<T>[]): number[] => R.map((content: ComicViewerItemProps<T>) => content.height)(items);\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (itemHeights: number[]): [number, number[]] => R.mapAccum(appender, 0, itemHeights);\n\nconst keyExtractor = <T, >(item: ComicViewerItemProps<T>) => `${item.sortKey}`;\n\nexport default function ComicViewer<T>(props: ComicViewerProps<T>) {\n const {\n data,\n errorDebounceMillis = 500,\n errorRetryCount = 3,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n onError,\n onScroll,\n onItemPress,\n getNextPage,\n viewerWidth,\n windowSize = 3,\n pageUnit,\n ListFooterComponent,\n ...otherProps\n } = props;\n\n const flatListRef = useRef<FlatList>(null);\n\n const errors = useRef<Map<number, ErrorInfo>>(new Map());\n\n const debounceTimeOut = useRef<NodeJS.Timeout | null>(null);\n\n const resourceString = R.toString(R.map((itemData: ComicViewerItemData) => itemData.url)(data));\n\n const imageWidth = Math.min(viewerWidth, 720);\n const initialItems = R.map((itemData: ComicViewerItemData<T>) => ({\n ...itemData,\n isViewable: false,\n width: imageWidth,\n height: (itemData.height * imageWidth) / itemData.width,\n }))(data);\n\n const [items, setItems] = useState<ComicViewerItemProps<T>[]>(initialItems);\n\n const initialItemState: ComicViewerItemState[] = R.map((itemData: ComicViewerItemData<T>) => ({\n sortKey: itemData.sortKey,\n state: STATE.UNLOAD,\n }))(data);\n\n const itemStates = useRef<Array<ComicViewerItemState>>(initialItemState);\n\n const itemHeights = [...getItemHeights(items)];\n const itemHeightAccum = getHeightAccum(itemHeights);\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const getItemLayout = useCallback((data: any, index: number) => {\n const offsets = R.prepend(0, itemHeightAccum[1]);\n\n return {\n length: itemHeights[index],\n offset: offsets[index],\n index,\n };\n }, [itemHeights]);\n\n const onViewableItemsChanged = useRef(({ viewableItems }: {\n viewableItems: Array<ViewToken>,\n }) => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n const viewableItemSortKeys = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);\n\n const newItems = R.map((prevItem: ComicViewerItemProps<T>) => ({\n ...prevItem,\n isViewable: R.includes(prevItem.sortKey, viewableItemSortKeys),\n }))([...prev]);\n\n return newItems;\n });\n });\n\n const itemLoadedHandler = useCallback((sortKey: number) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.LOADED;\n itemState.error = undefined;\n }, [itemStates]);\n\n const itemErrorHandler = useCallback((errorInfo: ErrorInfo) => {\n const { sortKey, count } = errorInfo;\n\n if (count >= errorRetryCount) {\n return;\n }\n\n errors.current.set(sortKey, errorInfo);\n\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.FAIL;\n itemState.error = errorInfo;\n\n const handleError = () => {\n const errorsArray = Array.from(errors.current.entries());\n const errorsInfo = R.map(([key, value]: [number, ErrorInfo]) => value)(errorsArray);\n\n onError && onError([...errorsInfo]);\n errors.current.clear();\n };\n\n if (debounceTimeOut.current) {\n clearTimeout(debounceTimeOut.current);\n }\n\n if (errors.current.size === pageUnit) {\n handleError();\n } else {\n debounceTimeOut.current = setTimeout(handleError, errorDebounceMillis);\n }\n }, [errors.current, itemStates]);\n\n const renderItem: ListRenderItem<ComicViewerItemProps<T>> = useCallback(({ item }) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === item.sortKey)(itemStates.current);\n\n const props = {\n ...item,\n itemState,\n errorRetryCount,\n onError: itemErrorHandler,\n onLoaded: itemLoadedHandler,\n onItemPress,\n getNextPage,\n };\n\n return <ViewerItem props={props}/>;\n }, [resourceString, itemErrorHandler, itemLoadedHandler, onItemPress]);\n\n useEffect(() => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n return R.map((prevItem: ComicViewerItemProps<T>) => {\n const currentData: ComicViewerItemData | undefined = R.find((currentItemData: ComicViewerItemData<T>) => prevItem.sortKey === currentItemData.sortKey)(data);\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === currentData?.sortKey)(itemStates.current);\n\n if (currentData\n && itemState\n && itemState.state !== STATE.LOADED\n && (currentData.url !== prevItem.url)) {\n return {\n ...prevItem,\n url: currentData.url,\n expiresAt: currentData.expiresAt,\n };\n }\n\n return prevItem;\n })([...prev]);\n ;\n });\n }, [resourceString]);\n\n useEffect(() => {\n const newItems = R.map((item: ComicViewerItemProps<T>) => ({\n ...item,\n width: imageWidth,\n height: (item.height * imageWidth) / item.width,\n }))(items);\n\n setItems(newItems);\n }, [imageWidth]);\n\n useEffect(() => {\n const totalHeight = itemHeightAccum[0];\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, [flatListRef.current]);\n\n return (\n <FlatList\n data={items}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n onScroll={onScroll}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n ListFooterComponent={ListFooterComponent}\n {...otherProps}\n />\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","FlatList","R","STATE","ViewerItem","getItemHeights","items","map","content","height","appender","left","right","getHeightAccum","itemHeights","mapAccum","keyExtractor","item","sortKey","ComicViewer","props","data","errorDebounceMillis","errorRetryCount","initialNumToRender","initialScrollPercentage","itemVisiblePercentThreshold","onError","onScroll","onItemPress","getNextPage","viewerWidth","windowSize","pageUnit","ListFooterComponent","otherProps","flatListRef","errors","Map","debounceTimeOut","resourceString","toString","itemData","url","imageWidth","Math","min","initialItems","isViewable","width","setItems","initialItemState","state","isEmpty","expiresAt","INIT","URL_LOADED","itemStates","itemHeightAccum","viewabilityConfig","getItemLayout","index","offsets","prepend","length","offset","onViewableItemsChanged","viewableItems","prev","viewableItemSortKeys","viewableItem","firstViewableSortKey","head","lastViewableItemSortKey","last","firstItem","lastItem","isNil","frontBoundary","max","backBoundary","viewableItemBoundary","range","newItems","prevItem","includes","itemLoadedHandler","itemState","find","current","LOADED","error","undefined","itemErrorHandler","errorInfo","count","set","FAIL","handleError","errorsArray","Array","from","entries","errorsInfo","key","value","clear","clearTimeout","size","setTimeout","renderItem","onLoaded","currentData","currentItemData","totalHeight","floor","scrollToOffset","animated"],"sources":["ComicViewer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { FlatList, ListRenderItem, ViewToken } from 'react-native';\nimport * as R from 'ramda';\nimport {\n ComicViewerItemData,\n ComicViewerItemState,\n default as ComicViewerProps,\n ErrorInfo,\n STATE,\n} from './ComicViewerProps';\nimport type ComicViewerItemProps from './ComicViewerItemProps';\nimport ViewerItem from './ViewerItem';\n\nconst getItemHeights = <T, >(items: ComicViewerItemProps<T>[]): number[] => R.map((content: ComicViewerItemProps<T>) => content.height)(items);\nconst appender = (left: number, right: number): [number, number] => [left + right, left + right];\nconst getHeightAccum = (itemHeights: number[]): [number, number[]] => R.mapAccum(appender, 0, itemHeights);\n\nconst keyExtractor = <T, >(item: ComicViewerItemProps<T>) => `${item.sortKey}`;\n\nexport default function ComicViewer<T>(props: ComicViewerProps<T>) {\n const {\n data,\n errorDebounceMillis = 500,\n errorRetryCount = 3,\n initialNumToRender = 1,\n initialScrollPercentage = 0,\n itemVisiblePercentThreshold = 0,\n onError,\n onScroll,\n onItemPress,\n getNextPage,\n viewerWidth,\n windowSize = 3,\n pageUnit,\n ListFooterComponent,\n ...otherProps\n } = props;\n\n const flatListRef = useRef<FlatList>(null);\n\n const errors = useRef<Map<number, ErrorInfo>>(new Map());\n\n const debounceTimeOut = useRef<NodeJS.Timeout | null>(null);\n\n const resourceString = R.toString(R.map((itemData: ComicViewerItemData) => itemData.url)(data));\n\n const imageWidth = Math.min(viewerWidth, 720);\n const initialItems = R.map((itemData: ComicViewerItemData<T>) => ({\n ...itemData,\n isViewable: false,\n width: imageWidth,\n height: (itemData.height * imageWidth) / itemData.width,\n }))(data);\n\n const [items, setItems] = useState<ComicViewerItemProps<T>[]>(initialItems);\n\n const initialItemState: ComicViewerItemState[] = R.map((itemData: ComicViewerItemData<T>) => ({\n sortKey: itemData.sortKey,\n state: R.isEmpty(itemData.expiresAt) ? STATE.INIT : STATE.URL_LOADED,\n }))(data);\n\n const itemStates = useRef<Array<ComicViewerItemState>>(initialItemState);\n\n const itemHeights = [...getItemHeights(items)];\n const itemHeightAccum = getHeightAccum(itemHeights);\n\n const viewabilityConfig = useMemo(() => ({\n itemVisiblePercentThreshold,\n }), [itemVisiblePercentThreshold]);\n\n const getItemLayout = useCallback((data: any, index: number) => {\n const offsets = R.prepend(0, itemHeightAccum[1]);\n\n return {\n length: itemHeights[index],\n offset: offsets[index],\n index,\n };\n }, [itemHeights]);\n\n const onViewableItemsChanged = useRef(({ viewableItems }: {\n viewableItems: Array<ViewToken>,\n }) => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n const viewableItemSortKeys: number[] = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);\n const firstViewableSortKey = R.head(viewableItemSortKeys);\n const lastViewableItemSortKey = R.last(viewableItemSortKeys);\n const firstItem = R.head(prev);\n const lastItem = R.last(prev);\n\n if (R.isNil(firstViewableSortKey)\n || R.isNil(lastViewableItemSortKey)\n || R.isNil(firstItem)\n || R.isNil(lastItem)\n ) {\n return prev;\n }\n\n const frontBoundary = R.max(firstItem.sortKey, firstViewableSortKey - 1);\n const backBoundary = R.min(lastItem.sortKey, lastViewableItemSortKey + 1);\n\n const viewableItemBoundary = R.range(frontBoundary, backBoundary + 1);\n const newItems = R.map((prevItem: ComicViewerItemProps<T>) => ({\n ...prevItem,\n isViewable: R.includes(prevItem.sortKey, viewableItemBoundary),\n }))([...prev]);\n\n return newItems;\n });\n });\n\n const itemLoadedHandler = useCallback((sortKey: number) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.LOADED;\n itemState.error = undefined;\n }, [itemStates]);\n\n const itemErrorHandler = useCallback((errorInfo: ErrorInfo) => {\n const { sortKey, count } = errorInfo;\n\n if (count >= errorRetryCount) {\n return;\n }\n\n errors.current.set(sortKey, errorInfo);\n\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === sortKey)(itemStates.current);\n\n if (R.isNil(itemState)) {\n return;\n }\n\n itemState.state = STATE.FAIL;\n itemState.error = errorInfo;\n\n const handleError = () => {\n const errorsArray = Array.from(errors.current.entries());\n const errorsInfo = R.map(([key, value]: [number, ErrorInfo]) => value)(errorsArray);\n\n onError && onError([...errorsInfo]);\n errors.current.clear();\n };\n\n if (debounceTimeOut.current) {\n clearTimeout(debounceTimeOut.current);\n }\n\n if (errors.current.size === pageUnit) {\n handleError();\n } else {\n debounceTimeOut.current = setTimeout(handleError, errorDebounceMillis);\n }\n }, [errors.current, itemStates]);\n\n const renderItem: ListRenderItem<ComicViewerItemProps<T>> = useCallback(({ item }) => {\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === item.sortKey)(itemStates.current);\n\n const props = {\n ...item,\n itemState,\n errorRetryCount,\n onError: itemErrorHandler,\n onLoaded: itemLoadedHandler,\n onItemPress,\n getNextPage,\n };\n\n return <ViewerItem props={props}/>;\n }, [resourceString, itemErrorHandler, itemLoadedHandler, onItemPress]);\n\n useEffect(() => {\n setItems((prev: ComicViewerItemProps<T>[]) => {\n return R.map((prevItem: ComicViewerItemProps<T>) => {\n const currentData: ComicViewerItemData | undefined = R.find((currentItemData: ComicViewerItemData<T>) => prevItem.sortKey === currentItemData.sortKey)(data);\n const itemState: ComicViewerItemState | undefined = R.find((state: ComicViewerItemState) => state.sortKey === currentData?.sortKey)(itemStates.current);\n\n if (currentData\n && itemState\n && itemState.state !== STATE.LOADED\n && (currentData.url !== prevItem.url)) {\n\n itemState.state = STATE.URL_LOADED;\n\n return {\n ...prevItem,\n url: currentData.url,\n expiresAt: currentData.expiresAt,\n };\n }\n\n return prevItem;\n })([...prev]);\n ;\n });\n }, [resourceString]);\n\n useEffect(() => {\n const newItems = R.map((item: ComicViewerItemProps<T>) => ({\n ...item,\n width: imageWidth,\n height: (item.height * imageWidth) / item.width,\n }))(items);\n\n setItems(newItems);\n }, [imageWidth]);\n\n useEffect(() => {\n const totalHeight = itemHeightAccum[0];\n const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);\n\n if (flatListRef.current) {\n flatListRef.current.scrollToOffset({ offset, animated: false });\n }\n }, [flatListRef.current]);\n\n return (\n <FlatList\n data={items}\n getItemLayout={getItemLayout}\n initialNumToRender={initialNumToRender}\n keyExtractor={keyExtractor}\n onViewableItemsChanged={onViewableItemsChanged.current}\n onScroll={onScroll}\n ref={flatListRef}\n renderItem={renderItem}\n viewabilityConfig={viewabilityConfig}\n windowSize={windowSize}\n ListFooterComponent={ListFooterComponent}\n {...otherProps}\n />\n );\n};\n"],"mappings":"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"}
|
|
@@ -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\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 * 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,8 +1,9 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Platform, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import * as R from 'ramda';
|
|
4
4
|
import { IconButton, Image, Spacer, useTheme } 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
9
|
const theme = useTheme();
|
|
@@ -74,6 +75,15 @@ function ViewerItem(_ref) {
|
|
|
74
75
|
});
|
|
75
76
|
}, [sortKey]);
|
|
76
77
|
const viewStyle = {
|
|
78
|
+
width: '100%',
|
|
79
|
+
height,
|
|
80
|
+
...Platform.select({
|
|
81
|
+
web: {
|
|
82
|
+
'cursor': 'default'
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
};
|
|
86
|
+
const imageStyle = {
|
|
77
87
|
width,
|
|
78
88
|
height
|
|
79
89
|
};
|
|
@@ -83,7 +93,7 @@ function ViewerItem(_ref) {
|
|
|
83
93
|
failed
|
|
84
94
|
} = props;
|
|
85
95
|
|
|
86
|
-
if (!isViewable
|
|
96
|
+
if (!(isViewable || isLoaded) || failed || (itemState === null || itemState === void 0 ? void 0 : itemState.state) === STATE.INIT) {
|
|
87
97
|
return /*#__PURE__*/React.createElement(View, {
|
|
88
98
|
style: [viewStyle, styles.init]
|
|
89
99
|
});
|
|
@@ -109,23 +119,18 @@ function ViewerItem(_ref) {
|
|
|
109
119
|
}));
|
|
110
120
|
}
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
return /*#__PURE__*/React.createElement(View, {
|
|
114
|
-
style: [viewStyle, styles.failed]
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return children ? /*#__PURE__*/React.createElement(Pressable, {
|
|
119
|
-
onPress: onItemPress
|
|
120
|
-
}, children) : null;
|
|
122
|
+
return children;
|
|
121
123
|
}, [isViewable, isLoaded, errorCount.current, url, onItemPress]);
|
|
122
124
|
useEffect(() => {
|
|
123
|
-
if (
|
|
125
|
+
if ((itemState === null || itemState === void 0 ? void 0 : itemState.state) === STATE.INIT) {
|
|
124
126
|
getNextPage === null || getNextPage === void 0 ? void 0 : getNextPage(sortKey);
|
|
125
127
|
}
|
|
126
128
|
}, []);
|
|
127
|
-
return /*#__PURE__*/React.createElement(
|
|
128
|
-
|
|
129
|
+
return /*#__PURE__*/React.createElement(TouchableOpacity, {
|
|
130
|
+
activeOpacity: 1,
|
|
131
|
+
onPress: onItemPress
|
|
132
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
133
|
+
style: [styles.root, viewStyle]
|
|
129
134
|
}, /*#__PURE__*/React.createElement(Image, {
|
|
130
135
|
disableOutline: true,
|
|
131
136
|
key: sortKey,
|
|
@@ -137,13 +142,15 @@ function ViewerItem(_ref) {
|
|
|
137
142
|
source: {
|
|
138
143
|
uri: url
|
|
139
144
|
},
|
|
140
|
-
style:
|
|
145
|
+
style: imageStyle,
|
|
141
146
|
square: true,
|
|
142
147
|
Placeholder: Placeholder
|
|
143
|
-
}));
|
|
148
|
+
})));
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
export default /*#__PURE__*/React.memo(ViewerItem, (prevProps, nextProps) => {
|
|
152
|
+
var _prevProps$props$item, _nextProps$props$item;
|
|
153
|
+
|
|
147
154
|
if (prevProps.props.isViewable !== nextProps.props.isViewable) {
|
|
148
155
|
return false;
|
|
149
156
|
}
|
|
@@ -156,6 +163,10 @@ export default /*#__PURE__*/React.memo(ViewerItem, (prevProps, nextProps) => {
|
|
|
156
163
|
return false;
|
|
157
164
|
}
|
|
158
165
|
|
|
166
|
+
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)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
159
170
|
return true;
|
|
160
171
|
});
|
|
161
172
|
//# 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","Platform","TouchableOpacity","View","R","IconButton","Image","Spacer","useTheme","Restart","STATE","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","select","web","imageStyle","Placeholder","children","state","INIT","borderRadius","color","uri","memo","prevProps","nextProps"],"sources":["ViewerItem.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform, TouchableOpacity, 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';\nimport { STATE } from './ComicViewerProps';\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 = {\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)\n || failed\n || itemState?.state === STATE.INIT\n ) {\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 return children;\n }, [isViewable, isLoaded, errorCount.current, url, onItemPress]);\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 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 />\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 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 if (prevProps.props.itemState?.state !== nextProps.props.itemState?.state) {\n return false;\n }\n\n return true;\n});\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
|
};
|
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.33",
|
|
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": "2c156aa34207beb3efdf1d1293b8b04269b9fd8a"
|
|
74
74
|
}
|
|
@@ -55,9 +55,9 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
55
55
|
const [items, setItems] = useState<ComicViewerItemProps<T>[]>(initialItems);
|
|
56
56
|
|
|
57
57
|
const initialItemState: ComicViewerItemState[] = R.map((itemData: ComicViewerItemData<T>) => ({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
sortKey: itemData.sortKey,
|
|
59
|
+
state: R.isEmpty(itemData.expiresAt) ? STATE.INIT : STATE.URL_LOADED,
|
|
60
|
+
}))(data);
|
|
61
61
|
|
|
62
62
|
const itemStates = useRef<Array<ComicViewerItemState>>(initialItemState);
|
|
63
63
|
|
|
@@ -82,11 +82,27 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
82
82
|
viewableItems: Array<ViewToken>,
|
|
83
83
|
}) => {
|
|
84
84
|
setItems((prev: ComicViewerItemProps<T>[]) => {
|
|
85
|
-
const viewableItemSortKeys = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);
|
|
86
|
-
|
|
85
|
+
const viewableItemSortKeys: number[] = R.map((viewableItem: ViewToken) => viewableItem.item.sortKey)(viewableItems);
|
|
86
|
+
const firstViewableSortKey = R.head(viewableItemSortKeys);
|
|
87
|
+
const lastViewableItemSortKey = R.last(viewableItemSortKeys);
|
|
88
|
+
const firstItem = R.head(prev);
|
|
89
|
+
const lastItem = R.last(prev);
|
|
90
|
+
|
|
91
|
+
if (R.isNil(firstViewableSortKey)
|
|
92
|
+
|| R.isNil(lastViewableItemSortKey)
|
|
93
|
+
|| R.isNil(firstItem)
|
|
94
|
+
|| R.isNil(lastItem)
|
|
95
|
+
) {
|
|
96
|
+
return prev;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const frontBoundary = R.max(firstItem.sortKey, firstViewableSortKey - 1);
|
|
100
|
+
const backBoundary = R.min(lastItem.sortKey, lastViewableItemSortKey + 1);
|
|
101
|
+
|
|
102
|
+
const viewableItemBoundary = R.range(frontBoundary, backBoundary + 1);
|
|
87
103
|
const newItems = R.map((prevItem: ComicViewerItemProps<T>) => ({
|
|
88
104
|
...prevItem,
|
|
89
|
-
isViewable: R.includes(prevItem.sortKey,
|
|
105
|
+
isViewable: R.includes(prevItem.sortKey, viewableItemBoundary),
|
|
90
106
|
}))([...prev]);
|
|
91
107
|
|
|
92
108
|
return newItems;
|
|
@@ -167,6 +183,9 @@ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
|
|
|
167
183
|
&& itemState
|
|
168
184
|
&& itemState.state !== STATE.LOADED
|
|
169
185
|
&& (currentData.url !== prevItem.url)) {
|
|
186
|
+
|
|
187
|
+
itemState.state = STATE.URL_LOADED;
|
|
188
|
+
|
|
170
189
|
return {
|
|
171
190
|
...prevItem,
|
|
172
191
|
url: currentData.url,
|
|
@@ -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;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Platform, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import * as R from 'ramda';
|
|
4
4
|
import type { PlaceholderProps } from '@fountain-ui/core';
|
|
5
5
|
import { IconButton, Image, Spacer, useTheme } from '@fountain-ui/core';
|
|
6
6
|
import { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';
|
|
7
7
|
import { Restart } from '@fountain-ui/icons';
|
|
8
8
|
import ComicViewerItemProps from './ComicViewerItemProps';
|
|
9
|
+
import { STATE } from './ComicViewerProps';
|
|
9
10
|
|
|
10
11
|
type PlaceholderStyles = NamedStylesStringUnion<'init' | 'failed' | 'reload' | 'root'>;
|
|
11
12
|
|
|
@@ -86,12 +87,23 @@ function ViewerItem<T>({ props }: { props: ComicViewerItemProps<T> }) {
|
|
|
86
87
|
});
|
|
87
88
|
}, [sortKey]);
|
|
88
89
|
|
|
89
|
-
const viewStyle = {
|
|
90
|
+
const viewStyle = {
|
|
91
|
+
width: '100%',
|
|
92
|
+
height,
|
|
93
|
+
...Platform.select({
|
|
94
|
+
web: { 'cursor': 'default' },
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const imageStyle = { width, height };
|
|
90
99
|
|
|
91
100
|
const Placeholder = useCallback((props: PlaceholderProps) => {
|
|
92
101
|
const { children, failed } = props;
|
|
93
102
|
|
|
94
|
-
if ((
|
|
103
|
+
if (!(isViewable || isLoaded)
|
|
104
|
+
|| failed
|
|
105
|
+
|| itemState?.state === STATE.INIT
|
|
106
|
+
) {
|
|
95
107
|
return <View style={[
|
|
96
108
|
viewStyle,
|
|
97
109
|
styles.init,
|
|
@@ -119,44 +131,41 @@ function ViewerItem<T>({ props }: { props: ComicViewerItemProps<T> }) {
|
|
|
119
131
|
</View>;
|
|
120
132
|
}
|
|
121
133
|
|
|
122
|
-
|
|
123
|
-
return (
|
|
124
|
-
<View style={[
|
|
125
|
-
viewStyle,
|
|
126
|
-
styles.failed,
|
|
127
|
-
]}/>
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return children ? (
|
|
132
|
-
<Pressable onPress={onItemPress}>
|
|
133
|
-
{children}
|
|
134
|
-
</Pressable>
|
|
135
|
-
) : null;
|
|
134
|
+
return children;
|
|
136
135
|
}, [isViewable, isLoaded, errorCount.current, url, onItemPress]);
|
|
137
136
|
|
|
138
137
|
useEffect(() => {
|
|
139
|
-
if (
|
|
138
|
+
if (itemState?.state === STATE.INIT) {
|
|
140
139
|
getNextPage?.(sortKey);
|
|
141
140
|
}
|
|
142
141
|
}, []);
|
|
143
142
|
|
|
144
143
|
return (
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
144
|
+
<TouchableOpacity
|
|
145
|
+
activeOpacity={1}
|
|
146
|
+
onPress={onItemPress}
|
|
147
|
+
>
|
|
148
|
+
<View
|
|
149
|
+
style={[
|
|
150
|
+
styles.root,
|
|
151
|
+
viewStyle,
|
|
152
|
+
]}
|
|
153
|
+
>
|
|
154
|
+
<Image
|
|
155
|
+
disableOutline={true}
|
|
156
|
+
key={sortKey}
|
|
157
|
+
disableLongClick={true}
|
|
158
|
+
disableDrag={true}
|
|
159
|
+
onLoad={onLoad}
|
|
160
|
+
onError={handleError}
|
|
161
|
+
loading={'eager'}
|
|
162
|
+
source={{ uri: url }}
|
|
163
|
+
style={imageStyle}
|
|
164
|
+
square={true}
|
|
165
|
+
Placeholder={Placeholder}
|
|
166
|
+
/>
|
|
167
|
+
</View>
|
|
168
|
+
</TouchableOpacity>
|
|
160
169
|
);
|
|
161
170
|
}
|
|
162
171
|
|
|
@@ -173,5 +182,9 @@ export default React.memo(ViewerItem, (prevProps, nextProps) => {
|
|
|
173
182
|
return false;
|
|
174
183
|
}
|
|
175
184
|
|
|
185
|
+
if (prevProps.props.itemState?.state !== nextProps.props.itemState?.state) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
176
189
|
return true;
|
|
177
190
|
});
|