@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.
@@ -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.UNLOAD
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, viewableItemSortKeys)
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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"}
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.STATE = void 0;
7
7
  const STATE = {
8
- UNLOAD: 'unload',
9
- LOADING: 'loading',
8
+ INIT: 'init',
9
+ URL_LOADED: 'url_loaded',
10
10
  LOADED: 'loaded',
11
11
  FAIL: 'fail'
12
12
  };
@@ -1 +1 @@
1
- {"version":3,"names":["STATE","UNLOAD","LOADING","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 UNLOAD: 'unload',\n LOADING: 'loading',\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,MAAM,EAAE,QADS;EAEjBC,OAAO,EAAE,SAFQ;EAGjBC,MAAM,EAAE,QAHS;EAIjBC,IAAI,EAAE;AAJW,CAAd"}
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 && !isLoaded || url === '') {
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
- if (failed) {
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 (url === '') {
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.View, {
143
- style: styles.root
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: viewStyle,
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.UNLOAD
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, viewableItemSortKeys)
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,6 +1,6 @@
1
1
  export const STATE = {
2
- UNLOAD: 'unload',
3
- LOADING: 'loading',
2
+ INIT: 'init',
3
+ URL_LOADED: 'url_loaded',
4
4
  LOADED: 'loaded',
5
5
  FAIL: 'fail'
6
6
  };
@@ -1 +1 @@
1
- {"version":3,"names":["STATE","UNLOAD","LOADING","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 UNLOAD: 'unload',\n LOADING: 'loading',\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,MAAM,EAAE,QADS;EAEjBC,OAAO,EAAE,SAFQ;EAGjBC,MAAM,EAAE,QAHS;EAIjBC,IAAI,EAAE;AAJW,CAAd"}
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 { Pressable, View } from 'react-native';
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 && !isLoaded || url === '') {
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
- if (failed) {
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 (url === '') {
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(View, {
128
- style: styles.root
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: viewStyle,
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 UNLOAD: "unload";
6
- readonly LOADING: "loading";
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.32",
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": "c2b92cc0980304e20d1fb3e025a5d230a46f2ff2"
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
- sortKey: itemData.sortKey,
59
- state: STATE.UNLOAD,
60
- }))(data);
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, viewableItemSortKeys),
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
- UNLOAD: 'unload',
7
- LOADING: 'loading',
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 { Pressable, View } from 'react-native';
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 = { width, height };
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 ((!isViewable && !isLoaded) || url === '') {
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
- if (failed) {
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 (url === '') {
138
+ if (itemState?.state === STATE.INIT) {
140
139
  getNextPage?.(sortKey);
141
140
  }
142
141
  }, []);
143
142
 
144
143
  return (
145
- <View style={styles.root}>
146
- <Image
147
- disableOutline={true}
148
- key={sortKey}
149
- disableLongClick={true}
150
- disableDrag={true}
151
- onLoad={onLoad}
152
- onError={handleError}
153
- loading={'eager'}
154
- source={{ uri: url }}
155
- style={viewStyle}
156
- square={true}
157
- Placeholder={Placeholder}
158
- />
159
- </View>
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
  });