@codeleap/mobile 3.25.0 → 3.25.3
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 +4 -6
- package/src/components/ActionIcon/index.tsx +37 -55
- package/src/components/ActionIcon/styles.ts +4 -2
- package/src/components/ActivityIndicator/index.tsx +64 -42
- package/src/components/ActivityIndicator/styles.ts +10 -1
- package/src/components/Autocomplete/index.tsx +54 -46
- package/src/components/Autocomplete/styles.ts +5 -2
- package/src/components/Autocomplete/types.ts +23 -13
- package/src/components/Avatar/index.tsx +71 -59
- package/src/components/Avatar/styles.ts +9 -1
- package/src/components/AvatarGroup/index.tsx +44 -30
- package/src/components/AvatarGroup/styles.ts +6 -0
- package/src/components/Backdrop/index.tsx +34 -51
- package/src/components/Backdrop/styles.ts +10 -5
- package/src/components/Badge/index.tsx +62 -36
- package/src/components/Badge/styles.ts +11 -3
- package/src/components/Button/index.tsx +82 -55
- package/src/components/Button/styles.ts +14 -13
- package/src/components/Calendar/index.tsx +29 -35
- package/src/components/Calendar/style.ts +6 -0
- package/src/components/Checkbox/index.tsx +64 -43
- package/src/components/Checkbox/styles.ts +6 -1
- package/src/components/ContentView/index.tsx +63 -0
- package/src/components/ContentView/styles.ts +8 -0
- package/src/components/DatePickerModal/index.tsx +65 -50
- package/src/components/DatePickerModal/styles.ts +10 -9
- package/src/components/DatePickerModal/types.ts +54 -36
- package/src/components/Drawer/index.tsx +28 -0
- package/src/components/Drawer/styles.ts +8 -0
- package/src/components/EmptyPlaceholder/index.tsx +63 -40
- package/src/components/EmptyPlaceholder/styles.ts +5 -0
- package/src/components/FileInput/index.tsx +49 -11
- package/src/components/FileInput/styles.ts +8 -0
- package/src/components/Grid/index.tsx +116 -84
- package/src/components/Grid/styles.ts +5 -0
- package/src/components/Icon/index.tsx +79 -44
- package/src/components/Icon/styles.ts +6 -0
- package/src/components/Image/index.tsx +78 -58
- package/src/components/Image/styles.ts +6 -1
- package/src/components/ImageView/Spotlight.tsx +4 -1
- package/src/components/ImageView/component.tsx +2 -1
- package/src/components/InputBase/index.tsx +24 -33
- package/src/components/InputBase/styles.ts +75 -66
- package/src/components/InputBase/types.ts +4 -3
- package/src/components/InputBase/utils.ts +4 -6
- package/src/components/InputLabel/index.tsx +38 -0
- package/src/components/InputLabel/styles.ts +7 -0
- package/src/components/List/PaginationIndicator.tsx +54 -0
- package/src/components/List/index.tsx +151 -99
- package/src/components/List/styles.ts +6 -0
- package/src/components/LoadingOverlay/index.tsx +29 -42
- package/src/components/LoadingOverlay/styles.ts +7 -7
- package/src/components/Modal/index.tsx +127 -80
- package/src/components/Modal/styles.ts +8 -0
- package/src/components/Navigation/Navigation.tsx +0 -1
- package/src/components/Navigation/types.ts +9 -2
- package/src/components/NumberIncrement/index.tsx +60 -50
- package/src/components/NumberIncrement/styles.ts +5 -0
- package/src/components/NumberIncrement/types.ts +39 -32
- package/src/components/Pager/index.tsx +94 -42
- package/src/components/Pager/styles.ts +13 -1
- package/src/components/RadioInput/index.tsx +57 -32
- package/src/components/RadioInput/styles.ts +7 -5
- package/src/components/RefreshControl/index.tsx +19 -39
- package/src/components/RefreshControl/styles.ts +6 -1
- package/src/components/Scroll/index.tsx +105 -89
- package/src/components/Scroll/styles.ts +5 -0
- package/src/components/Sections/index.tsx +161 -111
- package/src/components/Sections/styles.ts +5 -0
- package/src/components/SegmentedControl/Option.tsx +31 -46
- package/src/components/SegmentedControl/index.tsx +121 -86
- package/src/components/SegmentedControl/styles.ts +22 -15
- package/src/components/Select/index.tsx +82 -71
- package/src/components/Select/styles.ts +5 -3
- package/src/components/Select/types.ts +25 -20
- package/src/components/Slider/index.tsx +43 -58
- package/src/components/Slider/styles.ts +6 -15
- package/src/components/Slider/types.ts +14 -9
- package/src/components/Switch/index.tsx +56 -43
- package/src/components/Switch/styles.ts +7 -1
- package/src/components/Text/index.tsx +52 -56
- package/src/components/Text/styles.ts +7 -1
- package/src/components/TextInput/index.tsx +162 -49
- package/src/components/TextInput/styles.ts +8 -2
- package/src/components/Touchable/index.tsx +87 -44
- package/src/components/Touchable/styles.ts +9 -0
- package/src/components/View/index.tsx +92 -23
- package/src/components/View/styles.ts +6 -0
- package/src/components/components.ts +6 -2
- package/src/components/defaultStyles.ts +77 -0
- package/src/index.ts +0 -2
- package/src/modules/PressableRipple/type.ts +0 -1
- package/src/utils/KeyboardAware/context.tsx +2 -0
- package/src/utils/KeyboardAware/keyboardHooks.ts +2 -1
- package/src/utils/ModalManager/components.tsx +30 -1
- package/src/utils/ModalManager/context.tsx +4 -4
- package/src/utils/ModalManager/index.ts +4 -1
- package/src/utils/hooks.ts +1 -12
- package/src/Registry.ts +0 -52
- package/src/components/ActionIcon/types.ts +0 -15
- package/src/components/ActivityIndicator/types.ts +0 -9
- package/src/components/Avatar/types.ts +0 -23
- package/src/components/AvatarGroup/types.ts +0 -10
- package/src/components/Backdrop/types.ts +0 -14
- package/src/components/Badge/types.ts +0 -27
- package/src/components/Button/types.ts +0 -20
- package/src/components/Checkbox/types.ts +0 -13
- package/src/components/EmptyPlaceholder/types.ts +0 -21
- package/src/components/FileInput/types.ts +0 -27
- package/src/components/Grid/types.ts +0 -20
- package/src/components/Icon/types.ts +0 -15
- package/src/components/Image/types.ts +0 -18
- package/src/components/List/types.ts +0 -41
- package/src/components/LoadingOverlay/types.ts +0 -9
- package/src/components/Modal/types.ts +0 -41
- package/src/components/Pager/types.ts +0 -37
- package/src/components/PaginationIndicator/index.tsx +0 -51
- package/src/components/PaginationIndicator/styles.ts +0 -3
- package/src/components/PaginationIndicator/types.ts +0 -10
- package/src/components/RadioInput/types.ts +0 -31
- package/src/components/RefreshControl/types.ts +0 -9
- package/src/components/Scroll/types.ts +0 -21
- package/src/components/SearchInput/index.tsx +0 -90
- package/src/components/Sections/types.ts +0 -39
- package/src/components/SegmentedControl/types.ts +0 -31
- package/src/components/Switch/types.ts +0 -12
- package/src/components/Text/types.ts +0 -18
- package/src/components/TextInput/types.ts +0 -23
- package/src/components/Touchable/types.ts +0 -27
- package/src/components/View/types.ts +0 -13
- package/src/hooks/index.ts +0 -13
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
|
|
1
2
|
|
|
2
3
|
export type ScrollComposition = 'wrapper' |'content'
|
|
4
|
+
|
|
5
|
+
const createScrollStyle = createDefaultVariantFactory<ScrollComposition>()
|
|
6
|
+
|
|
7
|
+
export const ScrollPresets = includePresets(style => createScrollStyle(() => ({ content: style })))
|
|
@@ -1,118 +1,168 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { forwardRef } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
useDefaultComponentStyle,
|
|
5
|
+
ComponentVariants,
|
|
6
|
+
useCallback,
|
|
7
|
+
} from '@codeleap/common'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
RefreshControl,
|
|
11
|
+
StyleSheet,
|
|
12
|
+
RefreshControlProps,
|
|
13
|
+
SectionListRenderItemInfo,
|
|
14
|
+
SectionListProps as RNSectionListProps,
|
|
15
|
+
SectionList,
|
|
16
|
+
} from 'react-native'
|
|
17
|
+
import { View, ViewProps } from '../View'
|
|
18
|
+
import { EmptyPlaceholderProps } from '../EmptyPlaceholder'
|
|
19
|
+
import { StylesOf } from '../../types'
|
|
5
20
|
import { useKeyboardPaddingStyle } from '../../utils'
|
|
6
|
-
import {
|
|
7
|
-
import { AnyRecord, IJSX, StyledComponentProps, StyledComponentWithProps } from '@codeleap/styles'
|
|
8
|
-
import { MobileStyleRegistry } from '../../Registry'
|
|
9
|
-
import { useStylesFor } from '../../hooks'
|
|
10
|
-
|
|
21
|
+
import { SectionsComposition, SectionsPresets } from './styles'
|
|
11
22
|
export * from './styles'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const styles = useStylesFor(Sections.styleRegistryName, style)
|
|
33
|
-
|
|
34
|
-
const renderSeparator = useCallback(() => {
|
|
35
|
-
return <View style={styles?.separator} />
|
|
36
|
-
}, [styles?.separator])
|
|
37
|
-
|
|
38
|
-
const getItemPosition = (section, itemIdx) => {
|
|
39
|
-
const listLength = section?.length || 0
|
|
40
|
-
|
|
41
|
-
const isFirst = itemIdx === 0
|
|
42
|
-
const isLast = itemIdx === listLength - 1
|
|
43
|
-
const isOnly = isFirst && isLast
|
|
44
|
-
|
|
45
|
-
return { isFirst, isLast, isOnly }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const getSectionPosition = (data) => {
|
|
49
|
-
const listLength = props.sections?.length || 0
|
|
50
|
-
|
|
51
|
-
const isFirst = data.section.key === props.sections[0].key
|
|
52
|
-
const isLast = data.section.key === props.sections[listLength - 1].key
|
|
53
|
-
const isOnly = isFirst && isLast
|
|
54
|
-
|
|
55
|
-
return { isFirst, isLast, isOnly }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const renderSectionHeader = useCallback((data) => {
|
|
59
|
-
if (!props?.renderSectionHeader) return null
|
|
60
|
-
|
|
61
|
-
return props?.renderSectionHeader({ ...data, ...getSectionPosition(data) })
|
|
62
|
-
}, [props?.renderSectionHeader, props?.sections?.length])
|
|
63
|
-
|
|
64
|
-
const renderSectionFooter = useCallback((data) => {
|
|
65
|
-
if (!props?.renderSectionFooter) return null
|
|
66
|
-
|
|
67
|
-
return props?.renderSectionFooter({ ...data, ...getSectionPosition(data) })
|
|
68
|
-
}, [props?.renderSectionFooter, props?.sections?.length])
|
|
69
|
-
|
|
70
|
-
const renderItem = useCallback((data) => {
|
|
71
|
-
if (!props?.renderItem) return null
|
|
72
|
-
|
|
73
|
-
return props?.renderItem({ ...data, ...getItemPosition(data.section?.data, data?.index) })
|
|
74
|
-
|
|
75
|
-
}, [props?.renderItem, props?.sections?.length])
|
|
76
|
-
|
|
77
|
-
const separatorProp = props.separators
|
|
78
|
-
const isEmpty = !props.sections || !props.sections.length
|
|
79
|
-
const separator = !isEmpty && separatorProp == true && renderSeparator
|
|
80
|
-
|
|
81
|
-
const keyboardStyle = useKeyboardPaddingStyle([styles?.content, contentContainerStyle], keyboardAware)
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<SectionList
|
|
85
|
-
contentContainerStyle={keyboardStyle}
|
|
86
|
-
showsVerticalScrollIndicator={false}
|
|
87
|
-
// @ts-ignore
|
|
88
|
-
ref={ref}
|
|
89
|
-
ItemSeparatorComponent={separator}
|
|
90
|
-
{...props}
|
|
91
|
-
style={styles?.wrapper}
|
|
92
|
-
refreshControl={
|
|
93
|
-
!!onRefresh && (
|
|
94
|
-
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
renderItem={renderItem}
|
|
98
|
-
renderSectionHeader={renderSectionHeader}
|
|
99
|
-
renderSectionFooter={renderSectionFooter}
|
|
100
|
-
/>
|
|
101
|
-
)
|
|
102
|
-
},
|
|
103
|
-
) as StyledComponentWithProps<SectionListProps>
|
|
104
|
-
|
|
105
|
-
Sections.styleRegistryName = 'Sections'
|
|
106
|
-
Sections.elements = ['wrapper', 'content', 'separator']
|
|
107
|
-
Sections.rootElement = 'wrapper'
|
|
108
|
-
|
|
109
|
-
Sections.withVariantTypes = <S extends AnyRecord>(styles: S) => {
|
|
110
|
-
return Sections as (props: StyledComponentProps<SectionListProps, typeof styles>) => IJSX
|
|
23
|
+
|
|
24
|
+
export type DataboundSectionListPropsTypes = 'data' | 'renderItem' | 'keyExtractor' | 'getItemLayout'
|
|
25
|
+
|
|
26
|
+
export type AugmentedSectionRenderItemInfo<T> = SectionListRenderItemInfo<T> & {
|
|
27
|
+
isFirst: boolean
|
|
28
|
+
isLast: boolean
|
|
29
|
+
isOnly: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type ReplaceSectionListProps<P, T> = Omit<P, DataboundSectionListPropsTypes> & {
|
|
33
|
+
sections: T[]
|
|
34
|
+
keyExtractor?: (item: T, index: number) => string
|
|
35
|
+
renderItem: (data: AugmentedSectionRenderItemInfo<T>) => React.ReactElement
|
|
36
|
+
onRefresh?: () => void
|
|
37
|
+
getItemLayout?: ((
|
|
38
|
+
data: T,
|
|
39
|
+
index: number,
|
|
40
|
+
) => { length: number; offset: number; index: number })
|
|
41
|
+
fakeEmpty?: boolean
|
|
111
42
|
}
|
|
112
43
|
|
|
113
|
-
|
|
44
|
+
export * from './styles'
|
|
45
|
+
|
|
46
|
+
export type SectionListProps<
|
|
47
|
+
T = any[],
|
|
48
|
+
Data = T extends Array<infer D> ? D : never
|
|
49
|
+
> = ReplaceSectionListProps<RNSectionListProps<Data>, Data> &
|
|
50
|
+
Omit<ViewProps, 'variants'> & {
|
|
51
|
+
separators?: boolean
|
|
52
|
+
placeholder?: EmptyPlaceholderProps
|
|
53
|
+
styles?: StylesOf<SectionsComposition>
|
|
54
|
+
refreshControlProps?: Partial<RefreshControlProps>
|
|
55
|
+
fakeEmpty?: boolean
|
|
56
|
+
keyboardAware?: boolean
|
|
57
|
+
} & ComponentVariants<typeof SectionsPresets>
|
|
58
|
+
|
|
59
|
+
const defaultProps: Partial<SectionListProps> = {
|
|
114
60
|
keyboardShouldPersistTaps: 'handled',
|
|
61
|
+
refreshControlProps: {},
|
|
115
62
|
keyboardAware: true,
|
|
116
|
-
} as Partial<SectionListProps>
|
|
117
63
|
|
|
118
|
-
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const Sections = forwardRef<SectionList, SectionListProps>(
|
|
67
|
+
(sectionsProps, ref) => {
|
|
68
|
+
const {
|
|
69
|
+
variants = [],
|
|
70
|
+
style,
|
|
71
|
+
styles = {},
|
|
72
|
+
onRefresh,
|
|
73
|
+
component,
|
|
74
|
+
refreshing,
|
|
75
|
+
placeholder,
|
|
76
|
+
keyboardAware,
|
|
77
|
+
refreshControlProps,
|
|
78
|
+
contentContainerStyle,
|
|
79
|
+
|
|
80
|
+
fakeEmpty,
|
|
81
|
+
refreshControl,
|
|
82
|
+
...props
|
|
83
|
+
} = {
|
|
84
|
+
...defaultProps,
|
|
85
|
+
...sectionsProps,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const variantStyles = useDefaultComponentStyle<'u:Sections', typeof SectionsPresets>('u:Sections', {
|
|
89
|
+
variants,
|
|
90
|
+
styles,
|
|
91
|
+
transform: StyleSheet.flatten,
|
|
92
|
+
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const renderSeparator = useCallback(() => {
|
|
96
|
+
return (
|
|
97
|
+
<View style={variantStyles.separator}></View>
|
|
98
|
+
)
|
|
99
|
+
}, [variantStyles.separator])
|
|
100
|
+
|
|
101
|
+
const getItemPosition = (section, itemIdx) => {
|
|
102
|
+
const listLength = section?.length || 0
|
|
103
|
+
|
|
104
|
+
const isFirst = itemIdx === 0
|
|
105
|
+
const isLast = itemIdx === listLength - 1
|
|
106
|
+
const isOnly = isFirst && isLast
|
|
107
|
+
|
|
108
|
+
return { isFirst, isLast, isOnly }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const getSectionPosition = (data) => {
|
|
112
|
+
const listLength = props.sections?.length || 0
|
|
113
|
+
|
|
114
|
+
const isFirst = data.section.key === props.sections[0].key
|
|
115
|
+
const isLast = data.section.key === props.sections[listLength - 1].key
|
|
116
|
+
const isOnly = isFirst && isLast
|
|
117
|
+
|
|
118
|
+
return { isFirst, isLast, isOnly }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const renderSectionHeader = useCallback((data) => {
|
|
122
|
+
if (!props?.renderSectionHeader) return null
|
|
123
|
+
|
|
124
|
+
return props?.renderSectionHeader({ ...data, ...getSectionPosition(data) })
|
|
125
|
+
}, [props?.renderSectionHeader, props?.sections?.length])
|
|
126
|
+
|
|
127
|
+
const renderSectionFooter = useCallback((data) => {
|
|
128
|
+
if (!props?.renderSectionFooter) return null
|
|
129
|
+
|
|
130
|
+
return props?.renderSectionFooter({ ...data, ...getSectionPosition(data) })
|
|
131
|
+
}, [props?.renderSectionFooter, props?.sections?.length])
|
|
132
|
+
|
|
133
|
+
const renderItem = useCallback((data) => {
|
|
134
|
+
if (!props?.renderItem) return null
|
|
135
|
+
|
|
136
|
+
return props?.renderItem({ ...data, ...getItemPosition(data.section?.data, data?.index) })
|
|
137
|
+
|
|
138
|
+
}, [props?.renderItem, props?.sections?.length])
|
|
139
|
+
|
|
140
|
+
const separatorProp = props.separators
|
|
141
|
+
const isEmpty = !props.sections || !props.sections.length
|
|
142
|
+
const separator = !isEmpty && separatorProp == true && renderSeparator
|
|
143
|
+
|
|
144
|
+
const keyboardStyle = useKeyboardPaddingStyle([variantStyles.content, contentContainerStyle], keyboardAware)
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<SectionList
|
|
148
|
+
style={[variantStyles.wrapper, style]}
|
|
149
|
+
contentContainerStyle={keyboardStyle}
|
|
150
|
+
showsVerticalScrollIndicator={false}
|
|
151
|
+
// @ts-ignore
|
|
152
|
+
ref={ref}
|
|
153
|
+
ItemSeparatorComponent={separator}
|
|
154
|
+
{...props}
|
|
155
|
+
refreshControl={
|
|
156
|
+
!!onRefresh && (
|
|
157
|
+
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
renderItem={renderItem}
|
|
161
|
+
renderSectionHeader={renderSectionHeader}
|
|
162
|
+
renderSectionFooter={renderSectionFooter}
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
},
|
|
166
|
+
) as unknown as (<T = any>(props: SectionListProps<T>) => JSX.Element) & {
|
|
167
|
+
defaultProps: Partial<SectionListProps>
|
|
168
|
+
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
|
|
1
2
|
|
|
2
3
|
export type SectionsComposition = 'wrapper' |'content' | 'separator'
|
|
4
|
+
|
|
5
|
+
const createSectionsStyle = createDefaultVariantFactory<SectionsComposition>()
|
|
6
|
+
|
|
7
|
+
export const SectionsPresets = includePresets(style => createSectionsStyle(() => ({ content: style })))
|
|
@@ -1,66 +1,51 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { PropsOf } from '@codeleap/common'
|
|
2
|
+
import { IconPlaceholder, PropsOf } from '@codeleap/common'
|
|
3
3
|
import { StylesOf } from '../../types'
|
|
4
4
|
import { Text } from '../Text'
|
|
5
|
-
import { Touchable
|
|
5
|
+
import { Touchable } from '../Touchable'
|
|
6
6
|
import { SegmentedControlComposition } from './styles'
|
|
7
7
|
import { Icon } from '../Icon'
|
|
8
|
-
import { AppIcon } from '@codeleap/styles'
|
|
9
8
|
|
|
10
|
-
export type SegmentedControlOptionProps =
|
|
9
|
+
export type SegmentedControlOptionProps = PropsOf<typeof Touchable> & {
|
|
11
10
|
selected?: boolean
|
|
12
11
|
label: string
|
|
13
12
|
value: string
|
|
14
13
|
variantStyles?: StylesOf<SegmentedControlComposition>
|
|
15
14
|
textProps?: Omit<PropsOf<typeof Text>, 'key'>
|
|
16
|
-
icon?:
|
|
15
|
+
icon?: IconPlaceholder
|
|
17
16
|
badge?: React.ReactNode
|
|
18
|
-
debugName?: string
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
export const SegmentedControlOption = (props: SegmentedControlOptionProps) => {
|
|
22
|
-
const {
|
|
23
|
-
selected,
|
|
24
|
-
onPress,
|
|
25
|
-
debugName,
|
|
26
|
-
style,
|
|
27
|
-
variantStyles,
|
|
28
|
-
label,
|
|
29
|
-
value,
|
|
30
|
-
icon,
|
|
31
|
-
textProps,
|
|
32
|
-
badge = null,
|
|
33
|
-
...touchableProps
|
|
34
|
-
} = props
|
|
20
|
+
const { selected, onPress, debugName, style, variantStyles, label, value, icon, textProps, badge = null, ...touchableProps } = props
|
|
35
21
|
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
return <Touchable
|
|
23
|
+
debugName={`Segmented Control ${debugName}, option ${label}`}
|
|
24
|
+
noFeedback={selected}
|
|
25
|
+
|
|
26
|
+
styles={{
|
|
27
|
+
feedback: variantStyles.buttonFeedback,
|
|
28
|
+
}}
|
|
29
|
+
style={[variantStyles.button, selected && variantStyles['button:selected'], style]}
|
|
30
|
+
onPress={onPress}
|
|
31
|
+
{...touchableProps}
|
|
32
|
+
>
|
|
33
|
+
{
|
|
34
|
+
!!icon && (
|
|
35
|
+
<Icon name={icon} style={[variantStyles.icon]} />
|
|
36
|
+
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
<Text
|
|
40
|
+
text={label}
|
|
40
41
|
style={[
|
|
41
|
-
variantStyles
|
|
42
|
-
selected && variantStyles['
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
feedback: variantStyles.buttonFeedback,
|
|
46
|
-
}
|
|
42
|
+
variantStyles.text,
|
|
43
|
+
selected && variantStyles['text:selected'],
|
|
44
|
+
touchableProps?.disabled && variantStyles['text:disabled'],
|
|
47
45
|
]}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{!!icon ? <Icon name={icon} style={variantStyles?.icon} /> : null}
|
|
52
|
-
|
|
53
|
-
<Text
|
|
54
|
-
text={label}
|
|
55
|
-
style={[
|
|
56
|
-
variantStyles?.text,
|
|
57
|
-
selected && variantStyles['text:selected'],
|
|
58
|
-
touchableProps?.disabled && variantStyles['text:disabled'],
|
|
59
|
-
]}
|
|
60
|
-
{...textProps}
|
|
61
|
-
/>
|
|
46
|
+
{...textProps}
|
|
47
|
+
/>
|
|
48
|
+
{ badge }
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
</Touchable>
|
|
65
|
-
)
|
|
50
|
+
</Touchable>
|
|
66
51
|
}
|
|
@@ -1,19 +1,51 @@
|
|
|
1
|
-
import React, { useImperativeHandle, useMemo, useRef
|
|
2
|
-
import {
|
|
1
|
+
import React, { ReactElement, useImperativeHandle, useMemo, useRef } from 'react'
|
|
2
|
+
import { Scroll, ScrollProps, ScrollRef } from '../Scroll'
|
|
3
|
+
|
|
4
|
+
import { Easing, StyleSheet } from 'react-native'
|
|
5
|
+
import { FormTypes, getNestedStylesByKey, PropsOf, useCodeleapContext, useDefaultComponentStyle, useState } from '@codeleap/common'
|
|
6
|
+
import { SegmentedControlComposition, SegmentedControlPresets } from './styles'
|
|
7
|
+
import { Touchable } from '../Touchable'
|
|
8
|
+
import { StylesOf } from '../../types/utility'
|
|
3
9
|
import { Text } from '../Text'
|
|
4
10
|
import { View } from '../View'
|
|
5
|
-
import {
|
|
11
|
+
import { InputLabel } from '../InputLabel'
|
|
12
|
+
import { useAnimatedVariantStyles, TransitionConfig } from '../../utils'
|
|
6
13
|
import { SegmentedControlOption } from './Option'
|
|
7
|
-
import {
|
|
8
|
-
import { AnyRecord, IJSX, StyledComponentProps, StyledComponentWithProps, useTheme } from '@codeleap/styles'
|
|
9
|
-
import { MobileStyleRegistry } from '../../Registry'
|
|
10
|
-
import { useStylesFor } from '../../hooks'
|
|
14
|
+
import { SegmentedControlOptionProps } from './Option'
|
|
11
15
|
|
|
12
16
|
export * from './styles'
|
|
13
|
-
export * from './types'
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
export type SegmentedControlRef = ScrollRef & {
|
|
19
|
+
scrollTo: (index: number) => void
|
|
20
|
+
scrollToCurrent: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const DefaultBubble = (props: Partial<SegmentedControlProps>) => {
|
|
24
|
+
const {
|
|
25
|
+
style,
|
|
26
|
+
|
|
27
|
+
} = props
|
|
28
|
+
return <View
|
|
29
|
+
animated
|
|
30
|
+
style={style}
|
|
31
|
+
/>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type SegmentedControlProps<T = string> = ScrollProps & {
|
|
35
|
+
options: SegmentedControlOptionProps[]
|
|
36
|
+
onValueChange: (value: T) => any
|
|
37
|
+
value: T
|
|
38
|
+
debugName: string
|
|
39
|
+
animation?: TransitionConfig
|
|
40
|
+
textProps?: Partial<PropsOf<typeof Text>>
|
|
41
|
+
touchableProps?: Partial<PropsOf<typeof Touchable>>
|
|
42
|
+
styles?: StylesOf<SegmentedControlComposition>
|
|
43
|
+
scrollProps?: any
|
|
44
|
+
label?: FormTypes.Label
|
|
45
|
+
renderOption?: (props: SegmentedControlOptionProps) => JSX.Element
|
|
46
|
+
renderBubble?: (props: Partial<SegmentedControlProps>) => JSX.Element
|
|
47
|
+
getItemWidth?: (item: { label: string; value: T }, idx: number, arr: { label: string; value: T }[]) => number
|
|
48
|
+
scrollToCurrentOptionOnMount?: boolean
|
|
17
49
|
}
|
|
18
50
|
|
|
19
51
|
const defaultAnimation = {
|
|
@@ -22,9 +54,9 @@ const defaultAnimation = {
|
|
|
22
54
|
easing: Easing.linear,
|
|
23
55
|
}
|
|
24
56
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
57
|
+
const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControlProps>((props, ref) => {
|
|
58
|
+
|
|
59
|
+
const { Theme } = useCodeleapContext()
|
|
28
60
|
|
|
29
61
|
const {
|
|
30
62
|
options = [],
|
|
@@ -32,28 +64,32 @@ export const SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedC
|
|
|
32
64
|
debugName,
|
|
33
65
|
label,
|
|
34
66
|
value,
|
|
67
|
+
styles = {},
|
|
35
68
|
animation = {},
|
|
69
|
+
variants = [],
|
|
36
70
|
scrollProps = {},
|
|
37
|
-
getItemWidth = () => (
|
|
71
|
+
getItemWidth = (i) => (Theme.values.width - Theme.spacing.value(4)) / options.length,
|
|
38
72
|
renderBubble,
|
|
39
|
-
scrollToCurrentOptionOnMount,
|
|
73
|
+
scrollToCurrentOptionOnMount = true,
|
|
40
74
|
renderOption,
|
|
41
75
|
touchableProps,
|
|
42
|
-
style,
|
|
43
|
-
...viewProps
|
|
44
76
|
} = {
|
|
45
|
-
...
|
|
77
|
+
...(_SegmentedControl.defaultProps || {}),
|
|
46
78
|
...props,
|
|
47
79
|
}
|
|
48
80
|
|
|
49
81
|
const [bubbleWidth, setBubbleWidth] = useState(0)
|
|
50
82
|
|
|
51
83
|
const _animation = {
|
|
52
|
-
...defaultAnimation,
|
|
53
|
-
...animation,
|
|
84
|
+
...defaultAnimation, ...animation,
|
|
54
85
|
}
|
|
55
86
|
|
|
56
|
-
|
|
87
|
+
let variantStyles = useDefaultComponentStyle<'u:SegmentedControl', typeof SegmentedControlPresets>('u:SegmentedControl', {
|
|
88
|
+
styles,
|
|
89
|
+
transform: StyleSheet.flatten,
|
|
90
|
+
variants,
|
|
91
|
+
rootElement: 'scroll',
|
|
92
|
+
})
|
|
57
93
|
|
|
58
94
|
const scrollRef = useRef<SegmentedControlRef>(null)
|
|
59
95
|
|
|
@@ -112,8 +148,12 @@ export const SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedC
|
|
|
112
148
|
const BubbleView = renderBubble
|
|
113
149
|
const Option = renderOption
|
|
114
150
|
|
|
151
|
+
variantStyles = JSON.parse(JSON.stringify(variantStyles))
|
|
152
|
+
|
|
153
|
+
const labelStyles = getNestedStylesByKey('label', variantStyles)
|
|
154
|
+
|
|
115
155
|
const bubbleAnimation = useAnimatedVariantStyles({
|
|
116
|
-
variantStyles
|
|
156
|
+
variantStyles,
|
|
117
157
|
animatedProperties: [],
|
|
118
158
|
updater: () => {
|
|
119
159
|
'worklet'
|
|
@@ -127,74 +167,69 @@ export const SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedC
|
|
|
127
167
|
|
|
128
168
|
const largestWidth = useRef(0)
|
|
129
169
|
|
|
130
|
-
return (
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
>
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
170
|
+
return (<View style={variantStyles.wrapper}>
|
|
171
|
+
<InputLabel label={label} styles={labelStyles} required={false} />
|
|
172
|
+
<Scroll
|
|
173
|
+
horizontal
|
|
174
|
+
showsHorizontalScrollIndicator={false}
|
|
175
|
+
style={variantStyles.scroll}
|
|
176
|
+
contentContainerStyle={variantStyles.scrollContent}
|
|
177
|
+
{...scrollProps}
|
|
178
|
+
keyboardAware={{
|
|
179
|
+
enabled: false,
|
|
180
|
+
}}
|
|
181
|
+
ref={scrollRef}
|
|
182
|
+
>
|
|
183
|
+
<View style={variantStyles.innerWrapper}>
|
|
184
|
+
<BubbleView
|
|
185
|
+
options={options}
|
|
186
|
+
styles={variantStyles}
|
|
187
|
+
animated
|
|
188
|
+
style={[
|
|
189
|
+
variantStyles.selectedBubble,
|
|
190
|
+
props?.touchableProps?.disabled && variantStyles['selectedBubble:disabled'],
|
|
191
|
+
widthStyle,
|
|
192
|
+
bubbleAnimation,
|
|
193
|
+
]}
|
|
194
|
+
/>
|
|
195
|
+
{options.map((o, idx) => (
|
|
196
|
+
<Option
|
|
197
|
+
debugName={debugName}
|
|
198
|
+
label={o.label}
|
|
199
|
+
value={o.value}
|
|
200
|
+
icon={o.icon}
|
|
201
|
+
onPress={onPress(o.value, idx)}
|
|
202
|
+
key={idx}
|
|
203
|
+
style={widthStyle}
|
|
204
|
+
selected={value === o.value}
|
|
205
|
+
variantStyles={variantStyles}
|
|
206
|
+
onLayout={e => {
|
|
207
|
+
const { width } = e.nativeEvent.layout
|
|
208
|
+
if (width > largestWidth.current) {
|
|
209
|
+
largestWidth.current = width
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (idx === options.length - 1) {
|
|
213
|
+
setBubbleWidth(largestWidth.current)
|
|
214
|
+
largestWidth.current = 0
|
|
215
|
+
}
|
|
216
|
+
}}
|
|
217
|
+
{...touchableProps}
|
|
154
218
|
/>
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
value={o.value}
|
|
160
|
-
icon={o.icon}
|
|
161
|
-
onPress={onPress(o.value, idx)}
|
|
162
|
-
key={idx}
|
|
163
|
-
style={widthStyle}
|
|
164
|
-
selected={value === o.value}
|
|
165
|
-
variantStyles={styles}
|
|
166
|
-
onLayout={e => {
|
|
167
|
-
const { width } = e.nativeEvent.layout
|
|
168
|
-
if (width > largestWidth.current) {
|
|
169
|
-
largestWidth.current = width
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (idx === options.length - 1) {
|
|
173
|
-
setBubbleWidth(largestWidth.current)
|
|
174
|
-
largestWidth.current = 0
|
|
175
|
-
}
|
|
176
|
-
}}
|
|
177
|
-
{...touchableProps}
|
|
178
|
-
/>
|
|
179
|
-
))}
|
|
180
|
-
</View>
|
|
181
|
-
</ScrollView>
|
|
182
|
-
</View>
|
|
219
|
+
))}
|
|
220
|
+
</View>
|
|
221
|
+
</Scroll>
|
|
222
|
+
</View>
|
|
183
223
|
)
|
|
184
|
-
}) as StyledComponentWithProps<SegmentedControlProps>
|
|
185
224
|
|
|
186
|
-
|
|
187
|
-
SegmentedControl.elements = ['wrapper', 'selectedBubble', 'innerWrapper', 'scroll', 'text', 'icon', 'button', 'label', 'badge']
|
|
188
|
-
SegmentedControl.rootElement = 'scroll'
|
|
225
|
+
})
|
|
189
226
|
|
|
190
|
-
|
|
191
|
-
return SegmentedControl as (<T = string>(props: StyledComponentProps<SegmentedControlProps<T> & { ref?: React.Ref<SegmentedControlRef> }, typeof styles>) => IJSX)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
SegmentedControl.defaultProps = {
|
|
227
|
+
_SegmentedControl.defaultProps = {
|
|
195
228
|
renderBubble: DefaultBubble,
|
|
196
229
|
renderOption: SegmentedControlOption,
|
|
197
|
-
|
|
198
|
-
}
|
|
230
|
+
touchableProps: {},
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
type SegControlComponent = <T = string>(props: SegmentedControlProps<T> & { ref?: React.Ref<SegmentedControlRef> }) => ReactElement
|
|
199
234
|
|
|
200
|
-
|
|
235
|
+
export const SegmentedControl = _SegmentedControl as SegControlComponent
|