@codeleap/mobile 1.4.0 → 1.5.0

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 (83) hide show
  1. package/dist/components/ActivityIndicator.js +3 -4
  2. package/dist/components/ActivityIndicator.js.map +1 -1
  3. package/dist/components/Button.d.ts +1 -1
  4. package/dist/components/Button.js +1 -1
  5. package/dist/components/Button.js.map +1 -1
  6. package/dist/components/Checkbox/index.js +1 -1
  7. package/dist/components/Checkbox/index.js.map +1 -1
  8. package/dist/components/FileInput.js +2 -2
  9. package/dist/components/FileInput.js.map +1 -1
  10. package/dist/components/Icon.d.ts +2 -1
  11. package/dist/components/Icon.js +9 -3
  12. package/dist/components/Icon.js.map +1 -1
  13. package/dist/components/Image.d.ts +2 -1
  14. package/dist/components/Image.js +9 -3
  15. package/dist/components/Image.js.map +1 -1
  16. package/dist/components/Modal/styles.d.ts +1 -1
  17. package/dist/components/Modal/styles.js +9 -1
  18. package/dist/components/Modal/styles.js.map +1 -1
  19. package/dist/components/Navigation/Navigation.js +11 -3
  20. package/dist/components/Navigation/Navigation.js.map +1 -1
  21. package/dist/components/Navigation/types.js.map +1 -1
  22. package/dist/components/Navigation/utils.js +3 -0
  23. package/dist/components/Navigation/utils.js.map +1 -1
  24. package/dist/components/Overlay.js +1 -1
  25. package/dist/components/Overlay.js.map +1 -1
  26. package/dist/components/Pager/index.js +2 -2
  27. package/dist/components/Pager/index.js.map +1 -1
  28. package/dist/components/RadioInput/index.js +2 -2
  29. package/dist/components/RadioInput/index.js.map +1 -1
  30. package/dist/components/Select/index.js +10 -9
  31. package/dist/components/Select/index.js.map +1 -1
  32. package/dist/components/Switch.js.map +1 -1
  33. package/dist/components/TextInput.d.ts +2 -0
  34. package/dist/components/TextInput.js +3 -3
  35. package/dist/components/TextInput.js.map +1 -1
  36. package/dist/components/Touchable.d.ts +1 -1
  37. package/dist/modules/documentPicker.js.map +1 -1
  38. package/dist/utils/OSAlert.d.ts +3 -3
  39. package/dist/utils/OSAlert.js +63 -10
  40. package/dist/utils/OSAlert.js.map +1 -1
  41. package/package.json +3 -1
  42. package/src/components/ActivityIndicator.tsx +6 -7
  43. package/src/components/Animated.tsx +7 -7
  44. package/src/components/Button.tsx +12 -14
  45. package/src/components/Checkbox/index.tsx +7 -6
  46. package/src/components/Checkbox/styles.ts +2 -2
  47. package/src/components/ContentView.tsx +4 -4
  48. package/src/components/FileInput.tsx +28 -27
  49. package/src/components/Icon.tsx +14 -4
  50. package/src/components/Image.tsx +19 -9
  51. package/src/components/List.tsx +7 -7
  52. package/src/components/Modal/index.tsx +15 -15
  53. package/src/components/Modal/styles.ts +18 -3
  54. package/src/components/Navigation/Navigation.tsx +22 -15
  55. package/src/components/Navigation/index.tsx +2 -2
  56. package/src/components/Navigation/types.ts +3 -5
  57. package/src/components/Navigation/utils.tsx +25 -20
  58. package/src/components/Overlay.tsx +9 -8
  59. package/src/components/Pager/index.tsx +20 -21
  60. package/src/components/Pager/styles.ts +1 -1
  61. package/src/components/RadioInput/index.tsx +17 -16
  62. package/src/components/RadioInput/styles.ts +3 -3
  63. package/src/components/Scroll.tsx +7 -7
  64. package/src/components/Sections.tsx +100 -0
  65. package/src/components/Select/index.tsx +36 -33
  66. package/src/components/Select/styles.ts +7 -7
  67. package/src/components/Select/types.ts +18 -18
  68. package/src/components/Slider/Mark.tsx +7 -7
  69. package/src/components/Slider/Thumb.tsx +1 -1
  70. package/src/components/Slider/index.tsx +14 -14
  71. package/src/components/Slider/types.ts +18 -18
  72. package/src/components/Switch.tsx +6 -7
  73. package/src/components/Text.tsx +3 -3
  74. package/src/components/TextInput.tsx +14 -13
  75. package/src/components/Touchable.tsx +7 -7
  76. package/src/components/View.tsx +3 -3
  77. package/src/modules/documentPicker.ts +3 -4
  78. package/src/modules/index.d.ts +82 -82
  79. package/src/modules/types/documentPicker.d.ts +191 -191
  80. package/src/modules/types/fileTypes.ts +138 -138
  81. package/src/types/utility.ts +1 -1
  82. package/src/utils/OSAlert.ts +83 -27
  83. package/src/utils/misc.ts +2 -2
@@ -16,17 +16,17 @@ import { View, ViewProps } from './View'
16
16
 
17
17
  export type FlatListProps = KeyboardAwareFlatListProps<any> &
18
18
  ViewProps & {
19
- onRefresh?: () => void;
20
- refreshTimeout?: number;
21
- changeData?: any;
22
- separators?: boolean;
23
- };
19
+ onRefresh?: () => void
20
+ refreshTimeout?: number
21
+ changeData?: any
22
+ separators?: boolean
23
+ }
24
24
 
25
25
  const KeyboardAwareFlatList =
26
26
  KBDView as unknown as React.ForwardRefExoticComponent<
27
27
  ViewProps & {
28
- refreshControl?: JSX.Element;
29
- ref?: FlatList;
28
+ refreshControl?: JSX.Element
29
+ ref?: FlatList
30
30
  }
31
31
  >
32
32
 
@@ -25,21 +25,21 @@ import { Animated } from '../Animated'
25
25
  export * from './styles'
26
26
 
27
27
  export type ModalProps = Omit<ViewProps, 'variants' | 'styles'> & {
28
- variants?: ComponentVariants<typeof MobileModalStyles>['variants'];
29
- styles?: StylesOf<MobileModalComposition>;
30
- dismissOnBackdrop?: boolean;
31
- buttonProps?: ButtonProps;
32
- accessible?: boolean;
33
- showClose?: boolean;
34
- closable?: boolean;
35
- footer?: React.ReactNode;
36
- title?: React.ReactNode;
37
- debugName?: string;
38
- closeIconName?: IconPlaceholder;
39
- visible: boolean;
40
- toggle?: () => void;
41
- scroll?: boolean;
42
- };
28
+ variants?: ComponentVariants<typeof MobileModalStyles>['variants']
29
+ styles?: StylesOf<MobileModalComposition>
30
+ dismissOnBackdrop?: boolean
31
+ buttonProps?: ButtonProps
32
+ accessible?: boolean
33
+ showClose?: boolean
34
+ closable?: boolean
35
+ footer?: React.ReactNode
36
+ title?: React.ReactNode
37
+ debugName?: string
38
+ closeIconName?: IconPlaceholder
39
+ visible: boolean
40
+ toggle?: () => void
41
+ scroll?: boolean
42
+ }
43
43
 
44
44
  export const Modal: React.FC<ModalProps> = (modalProps) => {
45
45
  const {
@@ -31,11 +31,11 @@ export type MobileModalParts =
31
31
  | 'touchableBackdrop'
32
32
  | 'box:pose'
33
33
  | 'title'
34
- | `closeButton${Capitalize<ButtonComposition>}`;
34
+ | `closeButton${Capitalize<ButtonComposition>}`
35
35
 
36
36
  export type MobileModalComposition =
37
37
  | MobileModalParts
38
- | `${MobileModalParts}:visible`;
38
+ | `${MobileModalParts}:visible`
39
39
 
40
40
  const createModalStyle = createDefaultVariantFactory<MobileModalComposition>()
41
41
 
@@ -114,5 +114,20 @@ export const MobileModalStyles = {
114
114
  },
115
115
  }
116
116
  }),
117
- popup: createModalStyle((Theme) => ({})),
117
+ popup: createModalStyle((theme) => ({})),
118
+ fullscreen: createModalStyle((theme) => ({
119
+ overlay: {
120
+ backgroundColor: theme.colors.background,
121
+ },
122
+ 'overlay:visible': {
123
+ opacity: 1,
124
+ },
125
+ box: {
126
+ flex: 1,
127
+ borderRadius: 0,
128
+ width: theme.values.width,
129
+ height: theme.values.height,
130
+ ...theme.presets.center,
131
+ },
132
+ })),
118
133
  }
@@ -1,48 +1,55 @@
1
1
  // @ts-nocheck
2
2
  import * as React from 'react'
3
- import {
4
- TypeGuards,
3
+ import {
4
+ TypeGuards,
5
5
  } from '@codeleap/common'
6
6
  import { Icon } from '../Icon'
7
7
  import { NavigationProps, NavigatorType, PropTypes, TNavigators } from './types'
8
8
  import { Navigators } from './constants'
9
9
 
10
-
11
- export const Navigation = <T extends NavigatorType>({type, scenes, ...props}: NavigationProps<T>) => {
10
+ export const Navigation = <T extends NavigatorType>({ type, scenes, ...props }: NavigationProps<T>) => {
12
11
  const NavigationComponent = Navigators[type] as TNavigators[T]
13
12
 
13
+ const defaultProps = {}
14
+ if (type === 'Tab') {
15
+ defaultProps.screenOptions = { headerShown: false }
16
+ }
17
+ // console.log('render Navigation', { type, scenes, props, defaultProps })
14
18
 
15
- return <NavigationComponent.Navigator {...(props as any)}>
19
+ return <NavigationComponent.Navigator {...(props as any)} {...defaultProps}>
16
20
  {
17
21
  Object.entries(scenes).map(([name, content], idx) => {
18
22
  const isFunction = TypeGuards.isFunction(content)
19
-
23
+
20
24
  let screenProps = {
21
- name,
25
+ name,
22
26
  } as PropTypes[T]['Screen']
23
-
24
- if (isFunction){
27
+
28
+ if (isFunction) {
25
29
  screenProps.component = content
30
+ // console.log('Render NavigationScreen', { scenes, screenProps, content, isFunction }, 'PACKAGES')
26
31
  } else {
27
- screenProps.component = content?.component?.default || content?.component || content?.default
32
+ screenProps.component = content?.component?.default || content?.component || content?.default
28
33
  const nameParts = name.split('.')
34
+ const title = content?.title || nameParts[nameParts.length - 1] || name.replace('.', '')
29
35
 
30
36
  screenProps = {
31
37
  ...screenProps,
32
38
  options: (optionProps) => ({
33
- title: nameParts[nameParts.length - 1] || name.replace('.', ''),
34
- tabBarIcon: (style) => <Icon name={content?.icon} style={style}/>,
35
- ...(TypeGuards.isFunction(content.options) ? content.options(optionProps) : content.options),
39
+ title,
40
+ tabBarIcon: (style) => <Icon name={content?.icon} style={style}/>,
41
+ tabBarIconFocused: content?.iconFocused ? (style) => <Icon name={content?.iconFocused} style={style}/> : null,
42
+ ...(TypeGuards.isFunction(content.options) ? content.options(optionProps) : content.options),
36
43
  }),
37
44
  }
45
+ // console.log('Render NavigationScreen loop', { scenes, screenProps, content, title, isFunction, props }, 'PACKAGES')
38
46
  }
39
47
 
40
48
  return (
41
49
  // @ts-ignore
42
- <NavigationComponent.Screen
50
+ <NavigationComponent.Screen
43
51
  key={idx}
44
52
  {...screenProps}
45
-
46
53
  />
47
54
  )
48
55
  })
@@ -1,3 +1,3 @@
1
1
  export * from './Navigation'
2
- export * from './types'
3
- export * from './utils'
2
+ export * from './types'
3
+ export * from './utils'
@@ -1,7 +1,6 @@
1
1
  import { IconPlaceholder } from '@codeleap/common'
2
2
  import { Navigators } from './constants'
3
3
 
4
-
5
4
  export type TNavigators = typeof Navigators
6
5
  export type NavigatorType = keyof TNavigators
7
6
 
@@ -13,9 +12,9 @@ export type PropTypes = {
13
12
  }
14
13
  }
15
14
  export type SceneComponent<K extends NavigatorType> = PropTypes[K]['Screen']['component']
16
- export type SceneOptions<K extends NavigatorType> =
17
- { icon?: IconPlaceholder; default?:SceneComponent<K> } & PropTypes[K]['Screen']
18
- export type Scene<K extends NavigatorType> = SceneComponent<K> | SceneOptions<K>
15
+ export type SceneOptions<K extends NavigatorType> =
16
+ { icon?: IconPlaceholder; default?:SceneComponent<K> } & PropTypes[K]['Screen']
17
+ export type Scene<K extends NavigatorType> = SceneComponent<K> | SceneOptions<K>
19
18
 
20
19
  export type Scenes<K extends NavigatorType> = {
21
20
  [x:string] : Scene<K>
@@ -28,7 +27,6 @@ export type NavigationProps<T extends NavigatorType> = {
28
27
  scenes: Scenes<T>
29
28
  } & PropTypes[T]['Navigator']
30
29
 
31
-
32
30
  // export type NavigationStructure = {
33
31
  // [module:string] : {
34
32
  // scenes: Scenes,
@@ -1,47 +1,50 @@
1
- import React from 'react'
1
+ import React from 'react'
2
2
  import { Navigation } from './Navigation'
3
3
 
4
- export function createAppNavigation(Scenes:any ){
5
- const AllScenes = Object.entries<any>(Scenes).reduce((allScenes, [moduleName, content]) => {
6
-
4
+ export function createAppNavigation(Scenes:any) {
5
+
6
+ console.log('Creating app navigation', { Scenes }, 'PACKAGES')
7
+
8
+ const AllScenes = Object.entries<any>(Scenes).reduce((allScenes, [moduleName, content]) => {
9
+
7
10
  const subScenes = []
8
-
9
- for (const [name, sceneContent] of Object.entries(content.scenes)){
10
-
11
+
12
+ for (const [name, sceneContent] of Object.entries(content.scenes)) {
11
13
  subScenes.push(
12
- [`${moduleName}.${name}`, sceneContent],
14
+ [`${moduleName}.${name}`, sceneContent],
13
15
  )
14
16
  }
15
-
17
+
16
18
  return [
17
19
  ...allScenes,
18
20
  ...subScenes,
19
21
  ]
20
22
  }, [])
21
-
23
+
22
24
  const AppScenes = Object.fromEntries(AllScenes)
23
-
25
+
24
26
  const SCENES_RESULT = Object.fromEntries(
25
27
  Object.entries<any>(Scenes)
26
- .map(([S, { _ig_scenes, exclude, type, navigationProps, ...otherProps }]) => {
28
+ .map(([S, { _ig_scenes, exclude, type, navigationProps, ...otherProps }]) => {
27
29
  let filterScenes = null
28
-
29
- if (exclude){
30
+
31
+ if (exclude) {
30
32
  filterScenes = Object.fromEntries(
31
33
  AllScenes.filter(([path]) => !exclude.some(param => path.startsWith(param))),
32
34
  )
33
- }
34
-
35
- const Component = () => <Navigation
36
- type={type || 'Stack'}
37
- scenes={filterScenes || AppScenes}
35
+ }
36
+
37
+ const Component = () => <Navigation
38
+ type={type || 'Stack'}
39
+ scenes={filterScenes || AppScenes}
38
40
  screenOptions={{
39
41
  headerShown: false,
40
42
  ...navigationProps?.screenOptions,
41
43
  }}
42
44
  {...navigationProps}
43
45
  />
44
-
46
+ // console.log('SCENES_RESULT create', { _ig_scenes, exclude, type, navigationProps, otherProps })
47
+
45
48
  return [S, {
46
49
  ...otherProps,
47
50
  component: Component,
@@ -49,6 +52,8 @@ export function createAppNavigation(Scenes:any ){
49
52
  }),
50
53
  )
51
54
 
55
+ // console.log('SCENES_RESULT', SCENES_RESULT)
56
+
52
57
  return SCENES_RESULT
53
58
  }
54
59
 
@@ -16,14 +16,14 @@ import { StyleSheet, ViewProps } from 'react-native'
16
16
  import { AnimatedTouchable } from './Touchable'
17
17
 
18
18
  export type OverlayProps = ViewProps & {
19
- title?: ReactNode;
20
- visible?: boolean;
21
- showClose?: boolean;
22
- variants?: ComponentVariants<typeof OverlayStyles>;
23
- styles?: StylesOf<OverlayComposition>;
24
- style?: any;
25
- onPress?: () => void;
26
- } & React.ComponentPropsWithoutRef<typeof AnimatedTouchable>;
19
+ title?: ReactNode
20
+ visible?: boolean
21
+ showClose?: boolean
22
+ variants?: ComponentVariants<typeof OverlayStyles>
23
+ styles?: StylesOf<OverlayComposition>
24
+ style?: any
25
+ onPress?: () => void
26
+ } & React.ComponentPropsWithoutRef<typeof AnimatedTouchable>
27
27
 
28
28
  export const Overlay: React.FC<OverlayProps> = (overlayProps) => {
29
29
  const {
@@ -66,6 +66,7 @@ export const Overlay: React.FC<OverlayProps> = (overlayProps) => {
66
66
  variants={['icon']}
67
67
  icon={'close' as IconPlaceholder}
68
68
  style={variantStyles.closeButton}
69
+ debugName={'Close icon'}
69
70
  />
70
71
  )}
71
72
  </View>
@@ -23,20 +23,19 @@ import { MobilePagerStyles, PagerComposition } from './styles'
23
23
  export * from './styles'
24
24
 
25
25
  export type PagerProps = {
26
- variants?: ComponentVariants<typeof MobilePagerStyles>['variants'];
27
- styles?: StylesOf<PagerComposition>;
28
- page?: number;
29
- loop?: boolean;
30
- debug?: boolean;
31
- onPageChange?: (page: number) => void;
32
- };
26
+ variants?: ComponentVariants<typeof MobilePagerStyles>['variants']
27
+ styles?: StylesOf<PagerComposition>
28
+ page?: number
29
+ loop?: boolean
30
+ debug?: boolean
31
+ onPageChange?: (page: number) => void
32
+ }
33
33
 
34
34
  export type PagerRef = {
35
- forward(by?: number): void;
36
- back(by?: number): void;
37
- to(index?: number): void;
38
- };
39
-
35
+ forward(by?: number): void
36
+ back(by?: number): void
37
+ to(index?: number): void
38
+ }
40
39
 
41
40
  export const Pager = forwardRef<PagerRef, PagerProps>((pagerProps, ref) => {
42
41
  const {
@@ -107,7 +106,7 @@ export const Pager = forwardRef<PagerRef, PagerProps>((pagerProps, ref) => {
107
106
  setPage(propPage)
108
107
  }
109
108
  }, [propPage])
110
-
109
+
111
110
  useImperativeHandle(ref, () => pagerRef.current)
112
111
 
113
112
  const pagePoses = useMemo(() => {
@@ -138,9 +137,9 @@ export const Pager = forwardRef<PagerRef, PagerProps>((pagerProps, ref) => {
138
137
  variants={['absolute']}
139
138
  style={{ bottom: 0, left: 0, right: 0 }}
140
139
  >
141
- <Button text='previous' onPress={pagerRef.current.back} />
140
+ <Button text='previous' debugName='Previous Pager' onPress={pagerRef.current.back} />
142
141
  <Text text={page.toString()} />
143
- <Button text='next' onPress={pagerRef.current.forward} />
142
+ <Button text='next' debugName='Next Pager' onPress={pagerRef.current.forward} />
144
143
  </View>
145
144
  )}
146
145
  </View>
@@ -148,12 +147,12 @@ export const Pager = forwardRef<PagerRef, PagerProps>((pagerProps, ref) => {
148
147
  )
149
148
  })
150
149
  type PageProps = PagerProps & {
151
- idx: number;
152
- lastPage: number;
153
- page: number;
154
- pagePoses: any;
155
- style: any;
156
- };
150
+ idx: number
151
+ lastPage: number
152
+ page: number
153
+ pagePoses: any
154
+ style: any
155
+ }
157
156
  const Page: React.FC<PageProps> = (pageProps) => {
158
157
  const {
159
158
  children: child,
@@ -9,7 +9,7 @@ export type PagerComposition =
9
9
  | 'page:pose:previous'
10
10
  | 'page:pose:next'
11
11
  | 'page:pose:current'
12
- | 'wrapper';
12
+ | 'wrapper'
13
13
 
14
14
  const createPagerStyle = createDefaultVariantFactory<PagerComposition>()
15
15
 
@@ -15,9 +15,9 @@ import { MobileRadioInputStyles, MobileRadioInputComposition } from './styles'
15
15
  export * from './styles'
16
16
 
17
17
  type RadioItem<T extends unknown = any> = {
18
- value: T;
19
- label: ReactNode;
20
- };
18
+ value: T
19
+ label: ReactNode
20
+ }
21
21
 
22
22
  const getRadioStyle = (props) => useDefaultComponentStyle('RadioInput', props)
23
23
 
@@ -25,20 +25,20 @@ export type RadioButtonProps = Omit<
25
25
  ComponentPropsWithoutRef<typeof Touchable>,
26
26
  'style'
27
27
  > & {
28
- item: RadioItem;
29
- select: () => void;
30
- style: StylesOf<MobileRadioInputComposition>;
31
- checked: boolean;
32
- defaultValue?: number;
33
- };
28
+ item: RadioItem
29
+ select: () => void
30
+ style: StylesOf<MobileRadioInputComposition>
31
+ checked: boolean
32
+ defaultValue?: number
33
+ }
34
34
 
35
35
  export type RadioGroupProps<T> = {
36
- options: RadioItem<T>[];
37
- value: T;
38
- onValueChange(value: T): void;
39
- label: ReactNode;
40
- styles?: StylesOf<MobileRadioInputComposition>;
41
- } & ComponentVariants<typeof MobileRadioInputStyles>;
36
+ options: RadioItem<T>[]
37
+ value: T
38
+ onValueChange(value: T): void
39
+ label: ReactNode
40
+ styles?: StylesOf<MobileRadioInputComposition>
41
+ } & ComponentVariants<typeof MobileRadioInputStyles>
42
42
 
43
43
  export const RadioButton: React.FC<RadioButtonProps> = ({
44
44
  item,
@@ -48,7 +48,7 @@ export const RadioButton: React.FC<RadioButtonProps> = ({
48
48
  ...props
49
49
  }) => {
50
50
  return (
51
- <Touchable onPress={select} style={style.itemWrapper}>
51
+ <Touchable onPress={select} style={style.itemWrapper} debugName={'Change radioButton value'}>
52
52
  <View style={[style.button, checked && style['button:checked']]}>
53
53
  <View
54
54
  style={[style.buttonMark, checked && style['buttonMark:checked']]}
@@ -87,6 +87,7 @@ export const RadioGroup = <T extends unknown>(
87
87
  <View style={radioStyle.listWrapper}>
88
88
  {options?.map((item, idx) => (
89
89
  <RadioButton
90
+ debugName={'RadioButton'}
90
91
  item={item}
91
92
  key={idx}
92
93
  style={radioStyle}
@@ -2,14 +2,14 @@ import {
2
2
  createDefaultVariantFactory,
3
3
  RadioInputStyles,
4
4
  } from '@codeleap/common'
5
- type RadioParts = 'button' | 'itemWrapper' | 'text' | 'buttonMark';
5
+ type RadioParts = 'button' | 'itemWrapper' | 'text' | 'buttonMark'
6
6
 
7
- type RadioGroupParts = 'label' | 'wrapper' | 'list';
7
+ type RadioGroupParts = 'label' | 'wrapper' | 'list'
8
8
 
9
9
  export type MobileRadioInputComposition =
10
10
  | `${RadioParts}:checked`
11
11
  | RadioParts
12
- | RadioGroupParts;
12
+ | RadioGroupParts
13
13
 
14
14
  const createRadioStyle =
15
15
  createDefaultVariantFactory<MobileRadioInputComposition>()
@@ -16,18 +16,18 @@ import { ViewProps } from './View'
16
16
 
17
17
  export type ScrollProps = KeyboardAwareScrollViewProps &
18
18
  ViewProps & {
19
- onRefresh?: () => void;
20
- refreshTimeout?: number;
21
- changeData?: any;
19
+ onRefresh?: () => void
20
+ refreshTimeout?: number
21
+ changeData?: any
22
22
  styles?: ViewStyle
23
- };
23
+ }
24
24
 
25
25
  const KeyboardAwareScrollView =
26
26
  KBDView as unknown as React.ForwardRefExoticComponent<
27
27
  ViewProps & {
28
- refreshControl?: JSX.Element;
29
- ref?: ScrollView;
30
-
28
+ refreshControl?: JSX.Element
29
+ ref?: ScrollView
30
+
31
31
  } & ScrollViewProps
32
32
  >
33
33
 
@@ -0,0 +1,100 @@
1
+ import * as React from 'react'
2
+ import { forwardRef, useState } from 'react'
3
+ import {
4
+ deepEqual,
5
+ onUpdate,
6
+ useDefaultComponentStyle,
7
+ usePrevious,
8
+ useCodeleapContext,
9
+ } from '@codeleap/common'
10
+ import {
11
+ KeyboardAwareSectionListProps,
12
+ KeyboardAwareSectionList as KBDView,
13
+ } from 'react-native-keyboard-aware-scroll-view'
14
+ import { RefreshControl, SectionList } from 'react-native'
15
+ import { View, ViewProps } from './View'
16
+
17
+ export type SectionListProps = KeyboardAwareSectionListProps<any> &
18
+ ViewProps & {
19
+ onRefresh?: () => void
20
+ refreshTimeout?: number
21
+ changeData?: any
22
+ separators?: boolean
23
+ }
24
+
25
+ const KeyboardAwareSectionList =
26
+ KBDView as unknown as React.ForwardRefExoticComponent<
27
+ ViewProps & {
28
+ refreshControl?: JSX.Element
29
+ ref?: SectionList
30
+ }
31
+ >
32
+
33
+ export const Sections = forwardRef<SectionList, SectionListProps>(
34
+ (flatListProps, ref) => {
35
+ const {
36
+ variants = [],
37
+ style,
38
+ refreshTimeout = 3000,
39
+ changeData,
40
+ ...props
41
+ } = flatListProps
42
+ const hasRefresh = !!props.onRefresh
43
+ const [refreshing, setRefreshing] = useState(false)
44
+
45
+ const timer = React.useRef(null)
46
+ const previousData = usePrevious(changeData)
47
+
48
+ const onRefresh = () => {
49
+ if (timer.current) {
50
+ clearTimeout(timer.current)
51
+ }
52
+
53
+ setRefreshing(true)
54
+
55
+ props.onRefresh()
56
+
57
+ timer.current = setTimeout(() => {
58
+ setRefreshing(false)
59
+ }, refreshTimeout)
60
+ }
61
+ onUpdate(() => {
62
+ if (refreshing && !deepEqual(previousData, changeData)) {
63
+ setRefreshing(false)
64
+ if (timer.current) {
65
+ clearTimeout(timer.current)
66
+ }
67
+ }
68
+ }, [refreshing, changeData])
69
+ const { Theme } = useCodeleapContext()
70
+
71
+ const variantStyles = useDefaultComponentStyle('View', {
72
+ variants,
73
+ })
74
+
75
+ const renderSeparator = () => {
76
+ return (
77
+ <View variants={['separator']}></View>
78
+ )
79
+ }
80
+
81
+ const separatorProp = props.separators
82
+ const isEmpty = !props.data || !props.data.length
83
+ const separator = !isEmpty && separatorProp == true && renderSeparator
84
+
85
+ return (
86
+ <KeyboardAwareSectionList
87
+ style={[Theme.presets.full, style]}
88
+ contentContainerStyle={[variantStyles.wrapper]}
89
+ ref={ref as unknown as SectionList}
90
+ ItemSeparatorComponent={separator}
91
+ {...props}
92
+ refreshControl={
93
+ hasRefresh && (
94
+ <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
95
+ )
96
+ }
97
+ />
98
+ )
99
+ },
100
+ )