@fountain-ui/lab 1.21.1 → 2.0.0-beta.4

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.
Files changed (52) hide show
  1. package/build/commonjs/BottomSheet/BottomSheetNative.js +7 -1
  2. package/build/commonjs/BottomSheet/BottomSheetNative.js.map +1 -1
  3. package/build/commonjs/ComicViewer/ComicViewer.js +163 -0
  4. package/build/commonjs/ComicViewer/ComicViewer.js.map +1 -0
  5. package/build/commonjs/ComicViewer/ComicViewerItemProps.js +6 -0
  6. package/build/commonjs/ComicViewer/ComicViewerItemProps.js.map +1 -0
  7. package/build/commonjs/ComicViewer/ComicViewerProps.js +2 -0
  8. package/build/commonjs/ComicViewer/ComicViewerProps.js.map +1 -0
  9. package/build/commonjs/ComicViewer/ViewerItem.js +87 -0
  10. package/build/commonjs/ComicViewer/ViewerItem.js.map +1 -0
  11. package/build/commonjs/ComicViewer/index.js +16 -0
  12. package/build/commonjs/ComicViewer/index.js.map +1 -0
  13. package/build/commonjs/DateTimePicker/DateTimePicker.js +7 -1
  14. package/build/commonjs/DateTimePicker/DateTimePicker.js.map +1 -1
  15. package/build/commonjs/DateTimePicker/YearPicker.js +1 -0
  16. package/build/commonjs/DateTimePicker/YearPicker.js.map +1 -1
  17. package/build/commonjs/index.js +21 -0
  18. package/build/commonjs/index.js.map +1 -1
  19. package/build/module/BottomSheet/BottomSheetNative.js +7 -1
  20. package/build/module/BottomSheet/BottomSheetNative.js.map +1 -1
  21. package/build/module/ComicViewer/ComicViewer.js +146 -0
  22. package/build/module/ComicViewer/ComicViewer.js.map +1 -0
  23. package/build/module/ComicViewer/ComicViewerItemProps.js +2 -0
  24. package/build/module/ComicViewer/ComicViewerItemProps.js.map +1 -0
  25. package/build/module/ComicViewer/ComicViewerProps.js +2 -0
  26. package/build/module/ComicViewer/ComicViewerProps.js.map +1 -0
  27. package/build/module/ComicViewer/ViewerItem.js +71 -0
  28. package/build/module/ComicViewer/ViewerItem.js.map +1 -0
  29. package/build/module/ComicViewer/index.js +2 -0
  30. package/build/module/ComicViewer/index.js.map +1 -0
  31. package/build/module/DateTimePicker/DateTimePicker.js +7 -1
  32. package/build/module/DateTimePicker/DateTimePicker.js.map +1 -1
  33. package/build/module/DateTimePicker/YearPicker.js +1 -0
  34. package/build/module/DateTimePicker/YearPicker.js.map +1 -1
  35. package/build/module/index.js +2 -0
  36. package/build/module/index.js.map +1 -1
  37. package/build/typescript/ComicViewer/ComicViewer.d.ts +3 -0
  38. package/build/typescript/ComicViewer/ComicViewerItemProps.d.ts +12 -0
  39. package/build/typescript/ComicViewer/ComicViewerProps.d.ts +76 -0
  40. package/build/typescript/ComicViewer/ViewerItem.d.ts +7 -0
  41. package/build/typescript/ComicViewer/index.d.ts +3 -0
  42. package/build/typescript/index.d.ts +2 -0
  43. package/package.json +5 -6
  44. package/src/BottomSheet/BottomSheetNative.tsx +6 -0
  45. package/src/ComicViewer/ComicViewer.tsx +162 -0
  46. package/src/ComicViewer/ComicViewerItemProps.ts +15 -0
  47. package/src/ComicViewer/ComicViewerProps.ts +90 -0
  48. package/src/ComicViewer/ViewerItem.tsx +76 -0
  49. package/src/ComicViewer/index.ts +3 -0
  50. package/src/DateTimePicker/DateTimePicker.tsx +6 -0
  51. package/src/DateTimePicker/YearPicker.tsx +2 -1
  52. package/src/index.ts +3 -0
@@ -0,0 +1,162 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { FlatList, ListRenderItem, ViewToken } from 'react-native';
3
+ import * as R from 'ramda';
4
+ import { ComicViewerItemData, default as ComicViewerProps, ErrorInfo } from './ComicViewerProps';
5
+ import type ComicViewerItemProps from './ComicViewerItemProps';
6
+ import ViewerItem from './ViewerItem';
7
+
8
+ const getItemHeights = <T, >(items: ComicViewerItemProps<T>[]): number[] => R.map((content: ComicViewerItemProps<T>) => content.height)(items);
9
+ const appender = (left: number, right: number): [number, number] => [left + right, left + right];
10
+ const getHeightAccum = (itemHeights: number[]): [number, number[]] => R.mapAccum(appender, 0, itemHeights);
11
+
12
+ const keyExtractor = <T, >(item: ComicViewerItemProps<T>) => item.id;
13
+
14
+ export default function ComicViewer<T>(props: ComicViewerProps<T>) {
15
+ const {
16
+ data,
17
+ errorDebounceMillis = 500,
18
+ errorRetryCount = 3,
19
+ initialNumToRender = 1,
20
+ initialScrollPercentage = 0,
21
+ itemVisiblePercentThreshold = 0,
22
+ onError,
23
+ viewerWidth,
24
+ windowSize = 3,
25
+ ...otherProps
26
+ } = props;
27
+
28
+ const flatListRef = useRef<FlatList>(null);
29
+
30
+ const errors = useRef<Map<string, number>>(new Map());
31
+ const debounceTimeOut = useRef<NodeJS.Timeout | null>(null);
32
+
33
+ const resourceString = R.toString(R.map((itemData: ComicViewerItemData) => itemData.sourceUrl)(data));
34
+
35
+ const initialItems = R.map((itemData: ComicViewerItemData<T>) => ({
36
+ ...itemData,
37
+ isViewable: false,
38
+ width: viewerWidth,
39
+ height: (itemData.height * viewerWidth) / itemData.width,
40
+ }))(data);
41
+
42
+ const [items, setItems] = useState<ComicViewerItemProps<T>[]>(initialItems);
43
+
44
+ const itemHeights = getItemHeights(items);
45
+ const itemHeightAccum = getHeightAccum(itemHeights);
46
+
47
+ const viewabilityConfig = useMemo(() => ({
48
+ itemVisiblePercentThreshold,
49
+ }), [itemVisiblePercentThreshold]);
50
+
51
+ const getItemLayout = useCallback((data: any, index: number) => {
52
+ const offsets = R.prepend(0, itemHeightAccum[1]);
53
+
54
+ return {
55
+ length: itemHeights[index],
56
+ offset: offsets[index],
57
+ index,
58
+ };
59
+ }, [itemHeights]);
60
+
61
+ const onViewableItemsChanged = useRef(({ viewableItems }: {
62
+ viewableItems: Array<ViewToken>,
63
+ }) => {
64
+ setItems((prev: ComicViewerItemProps<T>[]) => {
65
+ const viewableItemIds = R.map((viewableItem: ViewToken) => viewableItem.item.id)(viewableItems);
66
+
67
+ return R.map((prevItem: ComicViewerItemProps<T>) => ({
68
+ ...prevItem,
69
+ isViewable: R.includes(prevItem.id, viewableItemIds),
70
+ }))([...prev]);
71
+ });
72
+ });
73
+
74
+ const onErrorHandler = (errors: ErrorInfo[]) => {
75
+ const isRetryLimited = R.any((error: ErrorInfo) => error.count >= errorRetryCount)(errors);
76
+
77
+ if (isRetryLimited) {
78
+ return;
79
+ }
80
+
81
+ onError && onError(errors);
82
+ };
83
+
84
+ const itemErrorHandler = useCallback((errorInfo: ErrorInfo) => {
85
+ errors.current.set(errorInfo.id, errorInfo.count);
86
+
87
+ if (debounceTimeOut.current) {
88
+ clearTimeout(debounceTimeOut.current);
89
+ }
90
+
91
+ debounceTimeOut.current = setTimeout(function () {
92
+ const errorsArray = Array.from(errors.current.entries());
93
+ const errorsInfo = R.map(([key, value]: [string, number]) => ({
94
+ id: key,
95
+ count: value,
96
+ }))(errorsArray);
97
+
98
+ onErrorHandler([...errorsInfo]);
99
+ errors.current.clear();
100
+ }, errorDebounceMillis);
101
+ }, [errorDebounceMillis, errors.current]);
102
+
103
+ const renderItem: ListRenderItem<ComicViewerItemProps<T>> = useCallback(({ item }) => {
104
+ const props = {
105
+ ...item,
106
+ onError: itemErrorHandler,
107
+ };
108
+
109
+ return <ViewerItem props={props}/>;
110
+ }, []);
111
+
112
+ useEffect(() => {
113
+ setItems((prev: ComicViewerItemProps<T>[]) => {
114
+ return R.map((prevItem: ComicViewerItemProps<T>) => {
115
+ const currentData = R.find((currentItemData: ComicViewerItemData<T>) => prevItem.id === currentItemData.id)(data);
116
+
117
+ if (currentData && (currentData.sourceUrl !== prevItem.sourceUrl)) {
118
+ return {
119
+ ...prevItem,
120
+ sourceUrl: currentData.sourceUrl,
121
+ };
122
+ }
123
+
124
+ return prevItem;
125
+ })([...prev]);
126
+ });
127
+ }, [resourceString]);
128
+
129
+ useEffect(() => {
130
+ const newItems = R.map((item: ComicViewerItemProps<T>) => ({
131
+ ...item,
132
+ width: viewerWidth,
133
+ height: (item.height * viewerWidth) / item.width,
134
+ }))(items);
135
+
136
+ setItems(newItems);
137
+ }, [viewerWidth]);
138
+
139
+ useEffect(() => {
140
+ const totalHeight = itemHeightAccum[0];
141
+ const offset = Math.floor((initialScrollPercentage / 100) * totalHeight);
142
+
143
+ if (flatListRef.current) {
144
+ flatListRef.current.scrollToOffset({ offset, animated: false });
145
+ }
146
+ }, [flatListRef.current]);
147
+
148
+ return (
149
+ <FlatList
150
+ data={items}
151
+ getItemLayout={getItemLayout}
152
+ initialNumToRender={initialNumToRender}
153
+ keyExtractor={keyExtractor}
154
+ onViewableItemsChanged={onViewableItemsChanged.current}
155
+ ref={flatListRef}
156
+ renderItem={renderItem}
157
+ viewabilityConfig={viewabilityConfig}
158
+ windowSize={windowSize}
159
+ {...otherProps}
160
+ />
161
+ );
162
+ };
@@ -0,0 +1,15 @@
1
+ import { ComicViewerItemData, ErrorInfo } from './ComicViewerProps';
2
+
3
+ type ComicViewerItemProps<T> = ComicViewerItemData<T> & {
4
+ /**
5
+ * FlatListItem is viewable in screen.
6
+ */
7
+ isViewable: boolean;
8
+
9
+ /**
10
+ * Error handler
11
+ */
12
+ onError?: (errorInfo: ErrorInfo) => void;
13
+ }
14
+
15
+ export default ComicViewerItemProps;
@@ -0,0 +1,90 @@
1
+ import { ComponentProps } from '@fountain-ui/core';
2
+
3
+ export interface ErrorInfo {
4
+ /**
5
+ * ComicViewerItemData.id.
6
+ */
7
+ id: string;
8
+
9
+ /**
10
+ * Number of times an error occurred.
11
+ */
12
+ count: number;
13
+ }
14
+
15
+ export type ComicViewerItemData<T = {}> = T & {
16
+ /**
17
+ * Image height.
18
+ */
19
+ height: number;
20
+
21
+ /**
22
+ * Unique value for identifying.
23
+ */
24
+ id: string;
25
+
26
+ /**
27
+ * Image sourceUrl for displaying.
28
+ */
29
+ sourceUrl: string;
30
+
31
+ /**
32
+ * Image width.
33
+ */
34
+ width: number;
35
+ }
36
+
37
+ export default interface ComicViewerProps<T> extends ComponentProps <{
38
+ /**
39
+ * Data for render.
40
+ */
41
+ data: ComicViewerItemData<T>[];
42
+
43
+ /**
44
+ * Delay Time to call the error handler.
45
+ * @default 500
46
+ */
47
+ errorDebounceMillis?: number;
48
+
49
+ /**
50
+ * How many times retry onError when same item error occur
51
+ * @default 3
52
+ */
53
+ errorRetryCount?: number;
54
+
55
+ /**
56
+ * How many items to render in the initial batch.
57
+ * @default 1
58
+ */
59
+ initialNumToRender?: number;
60
+
61
+ /**
62
+ * Start at initialScrollPercentage.
63
+ * If over 100, scroll to end.
64
+ * @default 0
65
+ */
66
+ initialScrollPercentage?: number;
67
+
68
+ /**
69
+ * The value for FlatList viewabilityConfig.itemVisiblePercentThreshold.
70
+ * @default 0
71
+ */
72
+ itemVisiblePercentThreshold?: number;
73
+
74
+ /**
75
+ * Handling all viewerItem errors at once.
76
+ * @param errors Array of ViewerItems errorInfo.
77
+ */
78
+ onError?: (errors: ErrorInfo[]) => void;
79
+
80
+ /**
81
+ * Comic viewer width.
82
+ */
83
+ viewerWidth: number;
84
+
85
+ /**
86
+ * The value for FlatList windowSize.
87
+ * @default 3
88
+ */
89
+ windowSize?: number;
90
+ }> {}
@@ -0,0 +1,76 @@
1
+ import React, { useCallback, useRef, useState } from 'react';
2
+ import { View } from 'react-native';
3
+ import { Image, StyleSheet } from '@fountain-ui/core';
4
+ import ComicViewerItemProps from './ComicViewerItemProps';
5
+
6
+ const styles = StyleSheet.create({
7
+ placeholder: {
8
+ backgroundColor: '#abcabc',
9
+ },
10
+ });
11
+
12
+ function ViewerItem<T>({ props }: { props: ComicViewerItemProps<T> }) {
13
+ const {
14
+ height,
15
+ id,
16
+ isViewable,
17
+ onError,
18
+ sourceUrl,
19
+ width,
20
+ } = props;
21
+
22
+ const [isLoaded, setIsLoaded] = useState(false);
23
+
24
+ const errorCount = useRef<number>(0);
25
+
26
+ const onLoad = useCallback(() => {
27
+ errorCount.current = 0;
28
+ setIsLoaded(true);
29
+ }, []);
30
+
31
+ const handleError = useCallback(() => {
32
+ errorCount.current = errorCount.current + 1;
33
+
34
+ onError && onError({
35
+ id,
36
+ count: errorCount.current
37
+ });
38
+ }, [id]);
39
+
40
+ const viewStyle = { width, height };
41
+
42
+ const Placeholder = () => (
43
+ <View style={[
44
+ viewStyle,
45
+ styles.placeholder,
46
+ ]}/>
47
+ );
48
+
49
+ if (!isViewable && !isLoaded) {
50
+ return <Placeholder/>;
51
+ }
52
+
53
+ return (
54
+ <Image
55
+ disableOutline={true}
56
+ key={sourceUrl}
57
+ onLoad={onLoad}
58
+ onError={handleError}
59
+ source={{ uri: sourceUrl }}
60
+ style={viewStyle}
61
+ square={true}
62
+ />
63
+ );
64
+ }
65
+
66
+ export default React.memo(ViewerItem, (prevProps, nextProps) => {
67
+ if (prevProps.props.isViewable !== nextProps.props.isViewable) {
68
+ return false;
69
+ }
70
+
71
+ if (prevProps.props.sourceUrl !== nextProps.props.sourceUrl) {
72
+ return false;
73
+ }
74
+
75
+ return true;
76
+ });
@@ -0,0 +1,3 @@
1
+ export { default } from './ComicViewer';
2
+ export type { ComicViewerItemData, default as ComicViewerProps, ErrorInfo } from './ComicViewerProps';
3
+ export type { default as ComicViewerItemProps } from './ComicViewerItemProps';
@@ -81,6 +81,12 @@ export default function DateTimePicker(props: DateTimePickerProps) {
81
81
  onPress={() => setYearPickerVisible(true)}
82
82
  />
83
83
  )}
84
+ theme={{
85
+ backgroundColor: theme.palette.background.default,
86
+ calendarBackground: theme.palette.background.default,
87
+ dayTextColor: theme.palette.text.primary,
88
+ textDisabledColor: theme.palette.text.hint,
89
+ }}
84
90
  />
85
91
  );
86
92
  };
@@ -61,6 +61,7 @@ const YearPicker = ({
61
61
  <Column>
62
62
  <Typography
63
63
  children={formatDate(date, locale)}
64
+ color={'textPrimary'}
64
65
  variant={'subtitle2'}
65
66
  />
66
67
  <FlatList
@@ -84,4 +85,4 @@ const YearPicker = ({
84
85
  );
85
86
  };
86
87
 
87
- export default YearPicker;
88
+ export default YearPicker;
package/src/index.ts CHANGED
@@ -13,6 +13,9 @@ export * from './FlipCard';
13
13
  export { default as ViewPager } from './ViewPager';
14
14
  export * from './ViewPager';
15
15
 
16
+ export { default as ComicViewer } from './ComicViewer';
17
+ export * from './ComicViewer';
18
+
16
19
  export { default as StatusBarProvider, useStatusBarContext } from './StatusBarProvider';
17
20
  export * from './StatusBarProvider';
18
21