@codeleap/mobile 3.24.2 → 3.25.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.
- package/package.json +6 -4
- package/src/Registry.ts +52 -0
- package/src/components/ActionIcon/index.tsx +55 -37
- package/src/components/ActionIcon/styles.ts +2 -4
- package/src/components/ActionIcon/types.ts +15 -0
- package/src/components/ActivityIndicator/index.tsx +42 -64
- package/src/components/ActivityIndicator/styles.ts +1 -10
- package/src/components/ActivityIndicator/types.ts +9 -0
- package/src/components/Autocomplete/index.tsx +46 -54
- package/src/components/Autocomplete/styles.ts +2 -5
- package/src/components/Autocomplete/types.ts +13 -23
- package/src/components/Avatar/index.tsx +59 -71
- package/src/components/Avatar/styles.ts +1 -9
- package/src/components/Avatar/types.ts +23 -0
- package/src/components/AvatarGroup/index.tsx +30 -44
- package/src/components/AvatarGroup/styles.ts +0 -6
- package/src/components/AvatarGroup/types.ts +10 -0
- package/src/components/Backdrop/index.tsx +51 -34
- package/src/components/Backdrop/styles.ts +5 -10
- package/src/components/Backdrop/types.ts +14 -0
- package/src/components/Badge/index.tsx +36 -62
- package/src/components/Badge/styles.ts +3 -11
- package/src/components/Badge/types.ts +27 -0
- package/src/components/Button/index.tsx +55 -82
- package/src/components/Button/styles.ts +13 -14
- package/src/components/Button/types.ts +20 -0
- package/src/components/Calendar/index.tsx +35 -29
- package/src/components/Checkbox/index.tsx +43 -64
- package/src/components/Checkbox/styles.ts +1 -6
- package/src/components/Checkbox/types.ts +13 -0
- package/src/components/DatePickerModal/index.tsx +50 -65
- package/src/components/DatePickerModal/styles.ts +9 -10
- package/src/components/DatePickerModal/types.ts +36 -54
- package/src/components/EmptyPlaceholder/index.tsx +40 -63
- package/src/components/EmptyPlaceholder/styles.ts +0 -5
- package/src/components/EmptyPlaceholder/types.ts +21 -0
- package/src/components/FileInput/index.tsx +11 -49
- package/src/components/FileInput/types.ts +27 -0
- package/src/components/Grid/index.tsx +84 -116
- package/src/components/Grid/styles.ts +0 -5
- package/src/components/Grid/types.ts +20 -0
- package/src/components/Icon/index.tsx +44 -79
- package/src/components/Icon/styles.ts +0 -6
- package/src/components/Icon/types.ts +15 -0
- package/src/components/Image/index.tsx +58 -78
- package/src/components/Image/styles.ts +1 -6
- package/src/components/Image/types.ts +18 -0
- package/src/components/ImageView/Spotlight.tsx +1 -4
- package/src/components/ImageView/component.tsx +1 -2
- package/src/components/InputBase/index.tsx +33 -24
- package/src/components/InputBase/styles.ts +66 -75
- package/src/components/InputBase/types.ts +3 -4
- package/src/components/InputBase/utils.ts +6 -4
- package/src/components/List/index.tsx +99 -151
- package/src/components/List/styles.ts +0 -6
- package/src/components/List/types.ts +41 -0
- package/src/components/LoadingOverlay/index.tsx +42 -29
- package/src/components/LoadingOverlay/styles.ts +7 -7
- package/src/components/LoadingOverlay/types.ts +9 -0
- package/src/components/Modal/index.tsx +80 -127
- package/src/components/Modal/styles.ts +0 -8
- package/src/components/Modal/types.ts +41 -0
- package/src/components/Navigation/Navigation.tsx +1 -0
- package/src/components/Navigation/types.ts +2 -9
- package/src/components/NumberIncrement/index.tsx +50 -60
- package/src/components/NumberIncrement/styles.ts +0 -5
- package/src/components/NumberIncrement/types.ts +32 -39
- package/src/components/Pager/index.tsx +42 -94
- package/src/components/Pager/styles.ts +1 -13
- package/src/components/Pager/types.ts +37 -0
- package/src/components/PaginationIndicator/index.tsx +51 -0
- package/src/components/PaginationIndicator/styles.ts +3 -0
- package/src/components/PaginationIndicator/types.ts +10 -0
- package/src/components/RadioInput/index.tsx +32 -57
- package/src/components/RadioInput/styles.ts +5 -7
- package/src/components/RadioInput/types.ts +31 -0
- package/src/components/RefreshControl/index.tsx +39 -19
- package/src/components/RefreshControl/styles.ts +1 -6
- package/src/components/RefreshControl/types.ts +9 -0
- package/src/components/Scroll/index.tsx +89 -105
- package/src/components/Scroll/styles.ts +0 -5
- package/src/components/Scroll/types.ts +21 -0
- package/src/components/SearchInput/index.tsx +90 -0
- package/src/components/Sections/index.tsx +111 -161
- package/src/components/Sections/styles.ts +0 -5
- package/src/components/Sections/types.ts +39 -0
- package/src/components/SegmentedControl/Option.tsx +46 -31
- package/src/components/SegmentedControl/index.tsx +86 -121
- package/src/components/SegmentedControl/styles.ts +15 -22
- package/src/components/SegmentedControl/types.ts +31 -0
- package/src/components/Select/index.tsx +71 -82
- package/src/components/Select/styles.ts +3 -5
- package/src/components/Select/types.ts +20 -25
- package/src/components/Slider/index.tsx +58 -43
- package/src/components/Slider/styles.ts +15 -6
- package/src/components/Slider/types.ts +9 -14
- package/src/components/Switch/index.tsx +43 -56
- package/src/components/Switch/styles.ts +1 -7
- package/src/components/Switch/types.ts +12 -0
- package/src/components/Text/index.tsx +56 -52
- package/src/components/Text/styles.ts +1 -7
- package/src/components/Text/types.ts +18 -0
- package/src/components/TextInput/index.tsx +49 -162
- package/src/components/TextInput/styles.ts +2 -8
- package/src/components/TextInput/types.ts +23 -0
- package/src/components/Touchable/index.tsx +44 -87
- package/src/components/Touchable/styles.ts +0 -9
- package/src/components/Touchable/types.ts +27 -0
- package/src/components/View/index.tsx +23 -92
- package/src/components/View/styles.ts +0 -6
- package/src/components/View/types.ts +13 -0
- package/src/components/components.ts +2 -6
- package/src/hooks/index.ts +13 -0
- package/src/index.ts +2 -0
- package/src/modules/PressableRipple/type.ts +1 -0
- package/src/utils/KeyboardAware/context.tsx +0 -2
- package/src/utils/KeyboardAware/keyboardHooks.ts +1 -2
- package/src/utils/ModalManager/components.tsx +1 -30
- package/src/utils/ModalManager/context.tsx +4 -4
- package/src/utils/ModalManager/index.ts +1 -4
- package/src/utils/hooks.ts +12 -1
- package/src/components/Calendar/style.ts +0 -6
- package/src/components/ContentView/index.tsx +0 -63
- package/src/components/ContentView/styles.ts +0 -8
- package/src/components/Drawer/index.tsx +0 -28
- package/src/components/Drawer/styles.ts +0 -8
- package/src/components/FileInput/styles.ts +0 -8
- package/src/components/InputLabel/index.tsx +0 -38
- package/src/components/InputLabel/styles.ts +0 -7
- package/src/components/List/PaginationIndicator.tsx +0 -54
- 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
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
129
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
|
|
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
|
|
26
|
-
|
|
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
|
-
|
|
41
|
-
badge = false,
|
|
17
|
+
badge,
|
|
42
18
|
badgeProps = {},
|
|
43
19
|
wrapperProps = {},
|
|
44
|
-
styles = {},
|
|
45
20
|
source,
|
|
46
21
|
...otherProps
|
|
47
|
-
} =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 =
|
|
42
|
+
const badgeStyles = useNestedStylesByKey('badge', styles)
|
|
88
43
|
|
|
89
44
|
const sized = {
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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={
|
|
57
|
+
return <Component {...otherProps} style={styles.icon} source={source} />
|
|
106
58
|
}
|
|
107
59
|
|
|
108
60
|
function areEqual(prevProps, nextProps) {
|
|
109
|
-
const check = ['name', 'style', '
|
|
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
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
|
|
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
|
|
27
|
-
import
|
|
28
|
-
import
|
|
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
|
|
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
|
-
|
|
51
|
-
fast = true,
|
|
20
|
+
fast,
|
|
52
21
|
spotlight = null,
|
|
53
|
-
resizeMode
|
|
22
|
+
resizeMode,
|
|
54
23
|
source,
|
|
55
|
-
withLoadingOverlay
|
|
56
|
-
maintainAspectRatio
|
|
24
|
+
withLoadingOverlay,
|
|
25
|
+
maintainAspectRatio,
|
|
57
26
|
...imageProps
|
|
58
|
-
} =
|
|
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 =
|
|
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:
|
|
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 =
|
|
94
|
+
const overlayStyle = useNestedStylesByKey('overlay', styles)
|
|
126
95
|
|
|
127
96
|
const loadingElement = React.useMemo(() => {
|
|
128
97
|
return showLoading ? (
|
|
129
|
-
<Loading visible={loading}
|
|
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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|