@codeleap/mobile 3.24.3 → 4.0.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 (131) hide show
  1. package/package.json +6 -4
  2. package/src/Registry.ts +52 -0
  3. package/src/components/ActionIcon/index.tsx +55 -37
  4. package/src/components/ActionIcon/styles.ts +2 -4
  5. package/src/components/ActionIcon/types.ts +15 -0
  6. package/src/components/ActivityIndicator/index.tsx +42 -64
  7. package/src/components/ActivityIndicator/styles.ts +1 -10
  8. package/src/components/ActivityIndicator/types.ts +9 -0
  9. package/src/components/Autocomplete/index.tsx +46 -54
  10. package/src/components/Autocomplete/styles.ts +2 -5
  11. package/src/components/Autocomplete/types.ts +13 -23
  12. package/src/components/Avatar/index.tsx +59 -71
  13. package/src/components/Avatar/styles.ts +1 -9
  14. package/src/components/Avatar/types.ts +23 -0
  15. package/src/components/AvatarGroup/index.tsx +30 -44
  16. package/src/components/AvatarGroup/styles.ts +0 -6
  17. package/src/components/AvatarGroup/types.ts +10 -0
  18. package/src/components/Backdrop/index.tsx +51 -34
  19. package/src/components/Backdrop/styles.ts +5 -10
  20. package/src/components/Backdrop/types.ts +14 -0
  21. package/src/components/Badge/index.tsx +36 -62
  22. package/src/components/Badge/styles.ts +3 -11
  23. package/src/components/Badge/types.ts +27 -0
  24. package/src/components/Button/index.tsx +55 -82
  25. package/src/components/Button/styles.ts +13 -14
  26. package/src/components/Button/types.ts +20 -0
  27. package/src/components/Calendar/index.tsx +35 -29
  28. package/src/components/Checkbox/index.tsx +43 -64
  29. package/src/components/Checkbox/styles.ts +1 -6
  30. package/src/components/Checkbox/types.ts +13 -0
  31. package/src/components/DatePickerModal/index.tsx +50 -65
  32. package/src/components/DatePickerModal/styles.ts +9 -10
  33. package/src/components/DatePickerModal/types.ts +36 -54
  34. package/src/components/EmptyPlaceholder/index.tsx +40 -63
  35. package/src/components/EmptyPlaceholder/styles.ts +0 -5
  36. package/src/components/EmptyPlaceholder/types.ts +21 -0
  37. package/src/components/FileInput/index.tsx +11 -49
  38. package/src/components/FileInput/types.ts +27 -0
  39. package/src/components/Grid/index.tsx +84 -116
  40. package/src/components/Grid/styles.ts +0 -5
  41. package/src/components/Grid/types.ts +20 -0
  42. package/src/components/Icon/index.tsx +44 -79
  43. package/src/components/Icon/styles.ts +0 -6
  44. package/src/components/Icon/types.ts +15 -0
  45. package/src/components/Image/index.tsx +58 -78
  46. package/src/components/Image/styles.ts +1 -6
  47. package/src/components/Image/types.ts +18 -0
  48. package/src/components/ImageView/Spotlight.tsx +1 -4
  49. package/src/components/ImageView/component.tsx +1 -2
  50. package/src/components/InputBase/index.tsx +33 -24
  51. package/src/components/InputBase/styles.ts +66 -75
  52. package/src/components/InputBase/types.ts +3 -4
  53. package/src/components/InputBase/utils.ts +6 -4
  54. package/src/components/List/index.tsx +99 -151
  55. package/src/components/List/styles.ts +0 -6
  56. package/src/components/List/types.ts +41 -0
  57. package/src/components/LoadingOverlay/index.tsx +42 -29
  58. package/src/components/LoadingOverlay/styles.ts +7 -7
  59. package/src/components/LoadingOverlay/types.ts +9 -0
  60. package/src/components/Modal/index.tsx +80 -127
  61. package/src/components/Modal/styles.ts +0 -8
  62. package/src/components/Modal/types.ts +41 -0
  63. package/src/components/Navigation/Navigation.tsx +1 -0
  64. package/src/components/Navigation/types.ts +2 -9
  65. package/src/components/NumberIncrement/index.tsx +50 -60
  66. package/src/components/NumberIncrement/styles.ts +0 -5
  67. package/src/components/NumberIncrement/types.ts +32 -39
  68. package/src/components/Pager/index.tsx +42 -94
  69. package/src/components/Pager/styles.ts +1 -13
  70. package/src/components/Pager/types.ts +37 -0
  71. package/src/components/PaginationIndicator/index.tsx +51 -0
  72. package/src/components/PaginationIndicator/styles.ts +3 -0
  73. package/src/components/PaginationIndicator/types.ts +10 -0
  74. package/src/components/RadioInput/index.tsx +32 -57
  75. package/src/components/RadioInput/styles.ts +5 -7
  76. package/src/components/RadioInput/types.ts +31 -0
  77. package/src/components/RefreshControl/index.tsx +39 -19
  78. package/src/components/RefreshControl/styles.ts +1 -6
  79. package/src/components/RefreshControl/types.ts +9 -0
  80. package/src/components/Scroll/index.tsx +89 -105
  81. package/src/components/Scroll/styles.ts +0 -5
  82. package/src/components/Scroll/types.ts +21 -0
  83. package/src/components/SearchInput/index.tsx +90 -0
  84. package/src/components/Sections/index.tsx +111 -161
  85. package/src/components/Sections/styles.ts +0 -5
  86. package/src/components/Sections/types.ts +39 -0
  87. package/src/components/SegmentedControl/Option.tsx +46 -31
  88. package/src/components/SegmentedControl/index.tsx +86 -121
  89. package/src/components/SegmentedControl/styles.ts +15 -22
  90. package/src/components/SegmentedControl/types.ts +31 -0
  91. package/src/components/Select/index.tsx +71 -82
  92. package/src/components/Select/styles.ts +3 -5
  93. package/src/components/Select/types.ts +20 -25
  94. package/src/components/Slider/index.tsx +58 -43
  95. package/src/components/Slider/styles.ts +15 -6
  96. package/src/components/Slider/types.ts +9 -14
  97. package/src/components/Switch/index.tsx +43 -56
  98. package/src/components/Switch/styles.ts +1 -7
  99. package/src/components/Switch/types.ts +12 -0
  100. package/src/components/Text/index.tsx +56 -52
  101. package/src/components/Text/styles.ts +1 -7
  102. package/src/components/Text/types.ts +18 -0
  103. package/src/components/TextInput/index.tsx +49 -162
  104. package/src/components/TextInput/styles.ts +2 -8
  105. package/src/components/TextInput/types.ts +23 -0
  106. package/src/components/Touchable/index.tsx +44 -87
  107. package/src/components/Touchable/styles.ts +0 -9
  108. package/src/components/Touchable/types.ts +27 -0
  109. package/src/components/View/index.tsx +23 -92
  110. package/src/components/View/styles.ts +0 -6
  111. package/src/components/View/types.ts +13 -0
  112. package/src/components/components.ts +2 -6
  113. package/src/hooks/index.ts +13 -0
  114. package/src/index.ts +2 -0
  115. package/src/modules/PressableRipple/type.ts +1 -0
  116. package/src/utils/KeyboardAware/context.tsx +0 -2
  117. package/src/utils/KeyboardAware/keyboardHooks.ts +1 -2
  118. package/src/utils/ModalManager/components.tsx +1 -30
  119. package/src/utils/ModalManager/context.tsx +4 -4
  120. package/src/utils/ModalManager/index.ts +1 -4
  121. package/src/utils/hooks.ts +12 -1
  122. package/src/components/Calendar/style.ts +0 -6
  123. package/src/components/ContentView/index.tsx +0 -63
  124. package/src/components/ContentView/styles.ts +0 -8
  125. package/src/components/Drawer/index.tsx +0 -28
  126. package/src/components/Drawer/styles.ts +0 -8
  127. package/src/components/FileInput/styles.ts +0 -8
  128. package/src/components/InputLabel/index.tsx +0 -38
  129. package/src/components/InputLabel/styles.ts +0 -7
  130. package/src/components/List/PaginationIndicator.tsx +0 -54
  131. package/src/components/defaultStyles.ts +0 -77
@@ -0,0 +1,27 @@
1
+ import { AnyRef, FormTypes } from '@codeleap/common'
2
+ import { DocumentPickerOptions } from 'react-native-document-picker'
3
+ import { Options } from 'react-native-image-crop-picker'
4
+ import { OSAlert } from '../../utils'
5
+
6
+ export type FileInputImageSource = 'camera' | 'library' | 'fs'
7
+
8
+ export type FileResult = FormTypes.AnyFile
9
+
10
+ export type FileInputRef = {
11
+ openFilePicker: (string?: FileInputImageSource) => Promise<FileResult[]>
12
+ }
13
+
14
+ export type FileInputProps = {
15
+ mode: 'hidden' | 'button'
16
+ onFileSelect?: (files: FileResult[]) => void
17
+ options?: DocumentPickerOptions<any>
18
+ ref?: AnyRef<FileInputRef>
19
+ type?: 'image' | 'anyFile'
20
+ alertProps?: Parameters<typeof OSAlert.ask>[0]
21
+ pickerOptions?: Partial<Options>
22
+ required?: boolean
23
+ onOpenCamera?: (resolve: (() => void)) => Promise<void>
24
+ onOpenFileSystem?: (resolve: (() => void)) => Promise<void>
25
+ onOpenGallery?: (resolve: (() => void)) => Promise<void>
26
+ onError?: (error: any) => void
27
+ }
@@ -1,135 +1,103 @@
1
- import * as React from 'react'
2
- import { forwardRef } from 'react'
3
- import {
4
- useDefaultComponentStyle,
5
- ComponentVariants,
6
- useCallback,
7
- useCodeleapContext,
8
- } from '@codeleap/common'
9
-
10
- import { StyleSheet, ListRenderItemInfo } from 'react-native'
1
+ import React, { useCallback, forwardRef, ComponentType } from 'react'
2
+ import { ListRenderItemInfo } from 'react-native'
11
3
  import { View, ViewProps } from '../View'
12
4
  import { EmptyPlaceholder } from '../EmptyPlaceholder'
13
5
  import { RefreshControl } from '../RefreshControl'
14
- import { List } from '../List'
15
- import { GridPresets } from './styles'
16
- import { FlatListProps, AugmentedRenderItemInfo } from '../List'
6
+ import { List, ListItem } from '../List'
17
7
  import { KeyboardAwareFlatList } from 'react-native-keyboard-aware-scroll-view'
8
+ import { GridProps } from './types'
9
+ import { AnyRecord, AppTheme, IJSX, StyledComponentProps, StyledComponentWithProps, Theme, useTheme } from '@codeleap/styles'
10
+ import { MobileStyleRegistry } from '../../Registry'
11
+ import { useStylesFor } from '../../hooks'
18
12
 
19
13
  export * from './styles'
14
+ export * from './types'
20
15
 
21
- export type DataboundFlatGridPropsTypes = 'data' | 'renderItem' | 'keyExtractor' | 'getItemLayout'
22
-
23
- export type GridAugmentedRenderItemInfo<T> = AugmentedRenderItemInfo<T> & {
24
- isFirstInRow: boolean
25
- isLastInRow: boolean
26
- isOnlyInRow: boolean
16
+ const RenderSeparator = (props: { separatorStyles: ViewProps['style'] }) => {
17
+ return <View style={props.separatorStyles} />
27
18
  }
28
19
 
29
- export type GridProps<
30
- T = any[],
31
- Data = T extends Array<infer D> ? D : never
32
- > = Omit<FlatListProps<T, Data>, 'variants' | 'renderItem'> & ComponentVariants<typeof GridPresets> & {
33
- spacing?: number
34
- itemDimension?: number
35
- renderItem: (data: GridAugmentedRenderItemInfo<T>) => React.ReactElement
36
- }
20
+ export const Grid = forwardRef<KeyboardAwareFlatList, GridProps>((flatGridProps, ref) => {
21
+ const {
22
+ style,
23
+ onRefresh,
24
+ refreshing,
25
+ placeholder,
26
+ refreshControlProps = {},
27
+ spacing,
28
+ numColumns,
29
+ renderItem: RenderItem,
30
+ ...props
31
+ } = {
32
+ ...Grid.defaultProps,
33
+ ...flatGridProps,
34
+ }
37
35
 
38
- const RenderSeparator = (props: { separatorStyles: ViewProps['style'] }) => {
39
- return (
40
- <View style={props.separatorStyles}></View>
41
- )
42
- }
36
+ const themeSpacing = useTheme(store => (store.current as AppTheme<Theme>)?.spacing)
43
37
 
44
- const defaultProps: Partial<GridProps> = {
45
- keyboardShouldPersistTaps: 'handled',
46
- refreshControlProps: {},
47
- }
38
+ const styles = useStylesFor(Grid.styleRegistryName, style)
39
+
40
+ const renderItem = useCallback((data: ListRenderItemInfo<any>) => {
41
+ if (!RenderItem) return null
42
+
43
+ const listLength = props?.data?.length || 0
48
44
 
49
- const GridCP = forwardRef<KeyboardAwareFlatList, GridProps>(
50
- (flatGridProps, ref) => {
51
- const {
52
- variants = [],
53
- style,
54
- styles = {},
55
- onRefresh,
56
- refreshing,
57
- placeholder,
58
- refreshControlProps = {},
59
- spacing,
60
- numColumns,
61
- ...props
62
- } = {
63
- ...defaultProps,
64
- ...flatGridProps,
65
- }
66
-
67
- const { Theme } = useCodeleapContext()
68
- const variantStyles = useDefaultComponentStyle<'u:Grid', typeof GridPresets>('u:Grid', {
69
- variants,
70
- styles,
71
- transform: StyleSheet.flatten,
72
- })
73
-
74
- const renderItem = useCallback((data: ListRenderItemInfo<any>) => {
75
- if (!props?.renderItem) return null
76
- const listLength = props?.data?.length || 0
77
-
78
- const isFirst = data.index === 0
79
- const isLast = data.index === listLength - 1
80
- const isOnly = isFirst && isLast
81
-
82
- const idx = data.index + 1
83
- const isLastInRow = !isFirst && idx % (numColumns) === 0
84
- const isFirstInRow = isFirst || data.index % numColumns === 0
85
- const isOnlyInRow = !isFirstInRow && !isLastInRow
86
-
87
- let gap = Theme.spacing.marginRight(spacing / 2)
88
- if (isLastInRow) gap = Theme.spacing.marginLeft(spacing / 2)
89
- else if (isOnlyInRow) gap = Theme.spacing.marginHorizontal(spacing / 2)
90
-
91
- const _itemProps = { isFirst, isLast, isOnly, isFirstInRow, isLastInRow, isOnlyInRow }
92
- const RenderItem = props?.renderItem
93
-
94
- return (
95
- <View style={{ ...variantStyles.itemWrapper, ...gap }}>
96
- <RenderItem {...data} {..._itemProps} />
97
- </View>
98
- )
99
- }, [props?.renderItem, props?.data?.length])
100
-
101
- const separatorStyles = { height: Theme.spacing.value(spacing), ...variantStyles.separator }
102
- const separator = props?.separators || (!!spacing ? <RenderSeparator separatorStyles={separatorStyles} /> : null)
103
- const refreshControl = !!onRefresh && <RefreshControl refreshing={refreshing} onRefresh={onRefresh} {...refreshControlProps} />
104
- const _gridProps = {
105
- ...props,
106
- ref: ref,
107
- ListEmptyComponent: <EmptyPlaceholder {...placeholder} />,
108
- ListHeaderComponentStyle: variantStyles.header,
109
- ListFooterComponentStyle: variantStyles.footer,
110
- ItemSeparatorComponent: separator,
111
- refreshControl,
112
- style: [variantStyles.wrapper, style],
113
- contentContainerStyle: [variantStyles.content, props?.contentContainerStyle],
114
- showsVerticalScrollIndicator: false,
115
- numColumns,
116
- renderItem,
117
- }
45
+ const isFirst = data.index === 0
46
+ const isLast = data.index === listLength - 1
47
+ const isOnly = isFirst && isLast
48
+
49
+ const idx = data.index + 1
50
+ const isLastInRow = !isFirst && idx % (numColumns) === 0
51
+ const isFirstInRow = isFirst || data.index % numColumns === 0
52
+ const isOnlyInRow = !isFirstInRow && !isLastInRow
53
+
54
+ let gap = themeSpacing?.marginRight?.(spacing / 2)
55
+ if (isLastInRow) gap = themeSpacing?.marginLeft?.(spacing / 2)
56
+ else if (isOnlyInRow) gap = themeSpacing?.marginHorizontal?.(spacing / 2)
57
+
58
+ const _itemProps = { isFirst, isLast, isOnly, isFirstInRow, isLastInRow, isOnlyInRow }
118
59
 
119
60
  return (
120
- // @ts-ignore
121
- <List
122
- {..._gridProps}
123
- />
61
+ <View style={[styles.itemWrapper, gap]}>
62
+ <RenderItem {...data} {..._itemProps} />
63
+ </View>
124
64
  )
125
- },
126
- )
65
+ }, [RenderItem, props?.data?.length])
127
66
 
128
- export type GridComponentType = (<T extends any[] = any[]>(props: GridProps<T>) => JSX.Element) & {
129
- defaultProps?: Partial<GridProps>
130
- }
67
+ const separatorStyles = { height: themeSpacing?.value?.(spacing), ...styles.separator }
68
+ const separator = props?.separators || (!!spacing ? <RenderSeparator separatorStyles={separatorStyles} /> : null)
69
+ const refreshControl = !!onRefresh && <RefreshControl refreshing={refreshing} onRefresh={onRefresh} {...refreshControlProps} />
131
70
 
132
- export const Grid = GridCP as unknown as GridComponentType
71
+ return (
72
+ <List
73
+ // @ts-expect-error
74
+ ref={ref}
75
+ {...props}
76
+ ListEmptyComponent={<EmptyPlaceholder {...placeholder} />}
77
+ ListHeaderComponentStyle={styles.header}
78
+ ListFooterComponentStyle={styles.footer}
79
+ ItemSeparatorComponent={separator as unknown as ComponentType}
80
+ refreshControl={refreshControl}
81
+ style={styles.wrapper}
82
+ contentContainerStyle={[styles.content, props?.contentContainerStyle]}
83
+ showsVerticalScrollIndicator={false}
84
+ numColumns={numColumns}
85
+ renderItem={renderItem}
86
+ />
87
+ )
88
+ }) as StyledComponentWithProps<GridProps>
133
89
 
134
- Grid.defaultProps = defaultProps
90
+ Grid.styleRegistryName = 'Grid'
91
+ Grid.elements = ['wrapper', 'content', 'separator', 'header', 'refreshControl', 'itemWrapper', 'footer']
92
+ Grid.rootElement = 'wrapper'
93
+
94
+ Grid.withVariantTypes = <S extends AnyRecord>(styles: S) => {
95
+ return Grid as (<T extends ListItem>(props: StyledComponentProps<GridProps<T>, typeof styles>) => IJSX)
96
+ }
97
+
98
+ Grid.defaultProps = {
99
+ keyboardShouldPersistTaps: 'handled',
100
+ refreshControlProps: {},
101
+ } as Partial<GridProps>
135
102
 
103
+ MobileStyleRegistry.registerComponent(Grid)
@@ -1,8 +1,3 @@
1
- import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
2
1
  import { ListComposition } from '../List'
3
2
 
4
3
  export type GridComposition = ListComposition | 'itemWrapper' | 'footer'
5
-
6
- const createGridStyle = createDefaultVariantFactory<GridComposition>()
7
-
8
- export const GridPresets = includePresets(style => createGridStyle(() => ({ content: style })))
@@ -0,0 +1,20 @@
1
+ import { StyledProp } from '@codeleap/styles'
2
+ import { FlatListProps, AugmentedRenderItemInfo, ListItem } from '../List'
3
+ import { GridComposition } from './styles'
4
+
5
+ export type GridAugmentedRenderItemInfo<T> =
6
+ AugmentedRenderItemInfo<T> &
7
+ {
8
+ isFirstInRow: boolean
9
+ isLastInRow: boolean
10
+ isOnlyInRow: boolean
11
+ }
12
+
13
+ export type GridProps<T extends ListItem = ListItem> =
14
+ Omit<FlatListProps<T>, 'style' | 'renderItem'> &
15
+ {
16
+ spacing?: number
17
+ itemDimension?: number
18
+ renderItem: (data: GridAugmentedRenderItemInfo<T>) => React.ReactElement
19
+ style?: StyledProp<GridComposition>
20
+ }
@@ -1,79 +1,34 @@
1
- import * as React from 'react'
2
- import {
3
- ComponentVariants,
4
-
5
- useDefaultComponentStyle,
6
- useCodeleapContext,
7
- arePropsEqual,
8
- IconPlaceholder,
9
- onUpdate,
10
- PropsOf,
11
- StylesOf,
12
- TypeGuards,
13
- getNestedStylesByKey,
14
- } from '@codeleap/common'
15
- import { StyleSheet } from 'react-native'
16
- export * from './styles'
17
-
18
- import {
19
- IconComposition,
20
- IconPresets,
21
- } from './styles'
22
- import { Badge, BadgeComponentProps } from '../Badge'
1
+ import React from 'react'
2
+ import { arePropsEqual, TypeGuards } from '@codeleap/common'
3
+ import { Badge } from '../Badge'
23
4
  import { View } from '../View'
5
+ import { IconProps } from './types'
6
+ import { useNestedStylesByKey, AnyRecord, StyledComponentProps, IJSX, useTheme, StyledComponentWithProps, AppTheme, Theme } from '@codeleap/styles'
7
+ import { MobileStyleRegistry } from '../../Registry'
8
+ import { useStylesFor } from '../../hooks'
24
9
 
25
- export type IconProps = {
26
- name: IconPlaceholder
27
- style?: any
28
- color?: string
29
- variants?: ComponentVariants<typeof IconPresets>['variants']
30
- wrapperProps?: Partial<PropsOf<typeof View>>
31
- size?: number
32
- styles?: StylesOf<IconComposition>
33
- source?: string
34
- } & BadgeComponentProps
10
+ export * from './styles'
11
+ export * from './types'
35
12
 
36
13
  export const IconComponent = (props: IconProps) => {
37
14
  const {
38
15
  name,
39
16
  style,
40
- variants,
41
- badge = false,
17
+ badge,
42
18
  badgeProps = {},
43
19
  wrapperProps = {},
44
- styles = {},
45
20
  source,
46
21
  ...otherProps
47
- } = props
48
-
49
- const { Theme, logger } = useCodeleapContext()
50
-
51
- const variantStyles = useDefaultComponentStyle<'u:Icon', typeof IconPresets>('u:Icon', {
52
- variants,
53
- transform: StyleSheet.flatten,
54
- styles: {
55
- icon: style,
56
- ...styles,
57
- },
58
- rootElement: 'icon',
59
- })
60
- const Component = Theme?.icons?.[name] || (source && Theme.icons.RenderSource)
61
-
62
- onUpdate(() => {
63
- if (!Component && !!name) {
64
- logger.warn(
65
- `Icon: No icon found in theme for name "${name}".`,
66
- { props: { style, name, variants, variantStyles } },
67
- 'Component',
68
- )
69
- } else if (!Component && !!source) {
70
- logger.warn('Icon: Cannot render source, no RenderSource component in Theme.icons', {
71
- source,
72
- props: { style, name, variants, variantStyles },
73
- Component,
74
- }, 'Component')
75
- }
76
- }, [name])
22
+ } = {
23
+ ...Icon.defaultProps,
24
+ ...props,
25
+ }
26
+
27
+ const icons = useTheme(store => (store.current as AppTheme<Theme>)?.icons)
28
+
29
+ const styles = useStylesFor(Icon.styleRegistryName, style)
30
+
31
+ const Component = icons?.[name]
77
32
 
78
33
  if (!name && !source) {
79
34
  return null
@@ -84,32 +39,42 @@ export const IconComponent = (props: IconProps) => {
84
39
  }
85
40
 
86
41
  if (badge || TypeGuards.isNumber(badge)) {
87
- const badgeStyles = getNestedStylesByKey('badge', variantStyles)
42
+ const badgeStyles = useNestedStylesByKey('badge', styles)
88
43
 
89
44
  const sized = {
90
- height: variantStyles.icon?.size || variantStyles.icon?.height || props?.size,
91
- width: variantStyles.icon?.size || variantStyles.icon?.width || props?.size,
45
+ // @ts-expect-error
46
+ height: styles.icon?.size || styles.icon?.height || props?.size,
47
+ // @ts-expect-error
48
+ width: styles.icon?.size || styles.icon?.width || props?.size,
92
49
  }
93
50
 
94
- const wrapperStyle = [
95
- sized,
96
- (variantStyles.iconBadgeWrapper ?? {}),
97
- ]
98
-
99
- return <View {...wrapperProps} style={wrapperStyle}>
100
- <Component {...otherProps} style={variantStyles.icon} source={source} />
101
- <Badge styles={badgeStyles} badge={badge} {...badgeProps} />
51
+ return <View {...wrapperProps} style={[sized, styles.iconBadgeWrapper]}>
52
+ <Component {...otherProps} style={styles.icon} source={source} />
53
+ <Badge style={badgeStyles} badge={badge} {...badgeProps} />
102
54
  </View>
103
55
  }
104
56
 
105
- return <Component {...otherProps} style={variantStyles.icon} source={source} />
57
+ return <Component {...otherProps} style={styles.icon} source={source} />
106
58
  }
107
59
 
108
60
  function areEqual(prevProps, nextProps) {
109
- const check = ['name', 'style', 'variants', 'renderEmptySpace', 'badgeProps', 'badge']
61
+ const check = ['name', 'style', 'renderEmptySpace', 'badgeProps', 'badge']
110
62
  const res = arePropsEqual(prevProps, nextProps, { check })
111
63
  return res
112
64
  }
113
65
 
114
- export const Icon = React.memo(IconComponent, areEqual) as typeof IconComponent
66
+ export const Icon = React.memo(IconComponent, areEqual) as StyledComponentWithProps<IconProps>
67
+
68
+ Icon.styleRegistryName = 'Icon'
69
+ Icon.elements = ['icon', 'iconBadgeWrapper', 'badge']
70
+ Icon.rootElement = 'icon'
71
+
72
+ Icon.defaultProps = {
73
+ badge: false,
74
+ } as Partial<IconProps>
75
+
76
+ Icon.withVariantTypes = <S extends AnyRecord>(styles: S) => {
77
+ return Icon as (props: StyledComponentProps<IconProps, typeof styles>) => IJSX
78
+ }
115
79
 
80
+ MobileStyleRegistry.registerComponent(Icon)
@@ -1,9 +1,3 @@
1
- import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
2
1
  import { BadgeComposition } from '../Badge'
3
2
 
4
3
  export type IconComposition = 'icon' | 'iconBadgeWrapper' | `badge${Capitalize<BadgeComposition>}`
5
-
6
- const createIconStyle = createDefaultVariantFactory<IconComposition>()
7
-
8
- export const IconPresets = includePresets((styles) => createIconStyle(() => ({ icon: styles })))
9
-
@@ -0,0 +1,15 @@
1
+ import { AppIcon, StyledProp } from '@codeleap/styles'
2
+ import { BadgeComponentProps } from '../Badge'
3
+ import { ViewProps } from '../View'
4
+ import { IconComposition } from './styles'
5
+
6
+ export type IconProps =
7
+ BadgeComponentProps &
8
+ {
9
+ name: AppIcon
10
+ style?: StyledProp<IconComposition>
11
+ color?: string
12
+ wrapperProps?: ViewProps
13
+ size?: number
14
+ source?: string
15
+ }
@@ -1,70 +1,37 @@
1
- import * as React from 'react'
2
- import {
3
- ComponentVariants,
4
- useDefaultComponentStyle,
5
- arePropsEqual,
6
- FormTypes,
7
- TypeGuards,
8
- getNestedStylesByKey,
9
- } from '@codeleap/common'
10
- import {
11
- Image as NativeImage,
12
- ImageProps as NativeImageProps,
13
- ImageStyle,
14
- StyleProp,
15
- StyleSheet,
16
- TextStyle,
17
- ViewStyle,
18
- } from 'react-native'
19
- import {
20
- ImageComposition,
21
- ImagePresets,
22
- } from './styles'
1
+ import React from 'react'
2
+ import { arePropsEqual, TypeGuards } from '@codeleap/common'
3
+ import { Image as NativeImage } from 'react-native'
23
4
  import { useImageSpotlight } from '../ImageView/Spotlight'
24
5
  import { Touchable } from '../Touchable'
25
6
  import { isFile, toMultipartFile } from '../../utils'
26
- import { LoadingOverlay, LoadingOverlayProps } from '../LoadingOverlay'
27
- import { StylesOf } from '../../types'
28
- import FastImage, { Source } from 'react-native-fast-image'
7
+ import { LoadingOverlay } from '../LoadingOverlay'
8
+ import FastImage from 'react-native-fast-image'
9
+ import { ImageProps } from './types'
10
+ import { AnyRecord, useNestedStylesByKey, IJSX, StyledComponentProps, StyledComponentWithProps } from '@codeleap/styles'
11
+ import { MobileStyleRegistry } from '../../Registry'
12
+ import { useStylesFor } from '../../hooks'
29
13
 
30
14
  export * from './styles'
15
+ export * from './types'
31
16
 
32
- export type ImageProps = Omit<NativeImageProps, 'source' | 'style'> & {
33
- variants?: ComponentVariants<typeof ImagePresets>['variants']
34
- fast?: boolean
35
- styles?: StylesOf<ImageComposition>
36
- style?: StyleProp<ImageStyle | TextStyle | ViewStyle>
37
- source:
38
- | Source
39
- | FormTypes.AnyFile
40
- resizeMode?: keyof typeof FastImage.resizeMode
41
- spotlight?: string
42
- maintainAspectRatio?: boolean
43
- withLoadingOverlay?: boolean | ((props: LoadingOverlayProps) => JSX.Element)
44
- }
45
-
46
- export const ImageComponent = (props:ImageProps) => {
17
+ export const Image = React.memo((props: ImageProps) => {
47
18
  const {
48
- variants,
49
19
  style,
50
- styles: componentStyleSheet = {},
51
- fast = true,
20
+ fast,
52
21
  spotlight = null,
53
- resizeMode = 'contain',
22
+ resizeMode,
54
23
  source,
55
- withLoadingOverlay = false,
56
- maintainAspectRatio = true,
24
+ withLoadingOverlay,
25
+ maintainAspectRatio,
57
26
  ...imageProps
58
- } = props
27
+ } = {
28
+ ...Image.defaultProps,
29
+ ...props,
30
+ }
59
31
 
60
- const variantStyles = useDefaultComponentStyle<'u:Image', typeof ImagePresets>('u:Image', {
61
- variants,
62
- styles: componentStyleSheet,
63
- transform: StyleSheet.flatten,
64
- })
65
32
  const [loading, setLoading] = React.useState(false)
66
33
 
67
- const styles = StyleSheet.flatten([variantStyles.wrapper, style])
34
+ const styles = useStylesFor(Image.styleRegistryName, style)
68
35
 
69
36
  let imSource = source
70
37
 
@@ -73,12 +40,14 @@ export const ImageComponent = (props:ImageProps) => {
73
40
  } else if (TypeGuards.isString(source)) {
74
41
  imSource = { uri: source }
75
42
  }
43
+
76
44
  const spotlightActions = useImageSpotlight(spotlight, props.source)
77
45
  const Wrapper = !!spotlight ? Touchable : ({ children }) => <>{children}</>
46
+
78
47
  const wrapperProps = {
79
48
  onPress: spotlightActions.onImagePressed,
80
49
  debugName: `Press spotlight image ${props.source}`,
81
- style: [variantStyles.touchable],
50
+ style: styles.touchable,
82
51
  android_ripple: null,
83
52
  }
84
53
 
@@ -122,23 +91,21 @@ export const ImageComponent = (props:ImageProps) => {
122
91
  const Loading = TypeGuards.isFunction(withLoadingOverlay) ? withLoadingOverlay : LoadingOverlay
123
92
  const showLoading = !!withLoadingOverlay
124
93
 
125
- const overlayStyle = React.useMemo(() => getNestedStylesByKey('overlay', variantStyles), [variantStyles])
94
+ const overlayStyle = useNestedStylesByKey('overlay', styles)
126
95
 
127
96
  const loadingElement = React.useMemo(() => {
128
97
  return showLoading ? (
129
- <Loading visible={loading} styles={overlayStyle}/>
130
-
98
+ <Loading visible={loading} style={overlayStyle} />
131
99
  ) : null
132
100
  }, [showLoading, loading])
133
101
 
134
102
  if (fast) {
135
103
  return (
136
104
  <Wrapper {...wrapperProps}>
137
-
138
105
  <FastImage
139
- style={[aspectRatioStyle, styles]}
106
+ style={[aspectRatioStyle, styles.wrapper]}
140
107
  // @ts-ignore
141
- tintColor={styles?.tintColor}
108
+ tintColor={styles?.wrapper?.tintColor}
142
109
  // @ts-ignore
143
110
  source={imSource}
144
111
  resizeMode={FastImage.resizeMode[resizeMode || 'contain']}
@@ -149,25 +116,38 @@ export const ImageComponent = (props:ImageProps) => {
149
116
  </Wrapper>
150
117
  )
151
118
  }
152
- return <Wrapper {...wrapperProps}>
153
- <NativeImage
154
- style={[aspectRatioStyle, styles]}
155
- resizeMode={resizeMode}
156
- source={imSource}
157
- {...(imageProps as any)}
158
- {...loadProps.current}
159
- />
160
- {
161
- loadingElement
162
- }
163
- </Wrapper>
164
- }
165
119
 
166
- function areEqual(prevProps, nextProps) {
167
- const check = ['source', 'style', 'variants', 'resizeMode', 'fast']
168
- const res = arePropsEqual(prevProps, nextProps, { check })
169
- return res
120
+ return (
121
+ <Wrapper {...wrapperProps}>
122
+ <NativeImage
123
+ resizeMode={resizeMode}
124
+ source={imSource}
125
+ {...(imageProps as any)}
126
+ {...loadProps.current}
127
+ style={[aspectRatioStyle, styles.wrapper]}
128
+ />
129
+
130
+ {loadingElement}
131
+ </Wrapper>
132
+ )
133
+ }, (prevProps, nextProps) => {
134
+ const equal = arePropsEqual(prevProps, nextProps, { check: ['source', 'style', 'resizeMode', 'fast'] })
135
+ return equal
136
+ }) as StyledComponentWithProps<ImageProps>
137
+
138
+ Image.styleRegistryName = 'Image'
139
+ Image.elements = ['wrapper', 'touchable', 'overlay']
140
+ Image.rootElement = 'wrapper'
141
+
142
+ Image.withVariantTypes = <S extends AnyRecord>(styles: S) => {
143
+ return Image as (props: StyledComponentProps<ImageProps, typeof styles>) => IJSX
170
144
  }
171
145
 
172
- export const Image = React.memo(ImageComponent, areEqual) as typeof ImageComponent
146
+ Image.defaultProps = {
147
+ fast: true,
148
+ resizeMode: 'contain',
149
+ withLoadingOverlay: false,
150
+ maintainAspectRatio: true,
151
+ }
173
152
 
153
+ MobileStyleRegistry.registerComponent(Image)
@@ -1,8 +1,3 @@
1
- import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
2
- import { LoadingOverlayComposition } from '../LoadingOverlay/styles'
1
+ import { LoadingOverlayComposition } from '../LoadingOverlay'
3
2
 
4
3
  export type ImageComposition = 'wrapper' | 'touchable' | `overlay${Capitalize<LoadingOverlayComposition>}`
5
- const createImageStyle = createDefaultVariantFactory<ImageComposition>()
6
-
7
- export const ImagePresets = includePresets((styles) => createImageStyle(() => ({ wrapper: styles, touchable: styles })))
8
-