@codeleap/mobile 2.3.8 → 2.3.10

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 (116) hide show
  1. package/package.json +1 -1
  2. package/src/components/ActionIcon/index.tsx +32 -0
  3. package/src/components/ActionIcon/styles.ts +97 -0
  4. package/src/components/ActivityIndicator/index.tsx +50 -0
  5. package/src/components/ActivityIndicator/styles.ts +68 -0
  6. package/src/components/Animated.tsx +34 -0
  7. package/src/components/AutoComplete/index.tsx +163 -0
  8. package/src/components/AutoComplete/styles.ts +44 -0
  9. package/src/components/Backdrop/index.tsx +48 -0
  10. package/src/components/Backdrop/styles.ts +33 -0
  11. package/src/components/Button/index.tsx +155 -0
  12. package/src/components/Button/styles.ts +129 -0
  13. package/src/components/Calendar/index.tsx +65 -0
  14. package/src/components/Calendar/style.ts +35 -0
  15. package/src/components/Calendar/types.ts +102 -0
  16. package/src/components/Checkbox/index.tsx +91 -0
  17. package/src/components/Checkbox/styles.ts +81 -0
  18. package/src/components/ContentView/index.tsx +63 -0
  19. package/src/components/ContentView/styles.ts +24 -0
  20. package/src/components/Drawer/index.tsx +33 -0
  21. package/src/components/Drawer/styles.ts +43 -0
  22. package/src/components/EmptyPlaceholder/index.tsx +88 -0
  23. package/src/components/EmptyPlaceholder/styles.ts +58 -0
  24. package/src/components/FileInput/index.tsx +181 -0
  25. package/src/components/FileInput/styles.ts +15 -0
  26. package/src/components/Grid/index.tsx +117 -0
  27. package/src/components/Grid/styles.ts +11 -0
  28. package/src/components/Icon/index.tsx +69 -0
  29. package/src/components/Icon/styles.ts +57 -0
  30. package/src/components/Image/index.tsx +91 -0
  31. package/src/components/Image/styles.ts +20 -0
  32. package/src/components/ImageView/Spotlight.tsx +157 -0
  33. package/src/components/ImageView/component.tsx +38 -0
  34. package/src/components/ImageView/index.ts +2 -0
  35. package/src/components/InputLabel/index.tsx +38 -0
  36. package/src/components/InputLabel/styles.ts +19 -0
  37. package/src/components/List/PaginationIndicator.tsx +71 -0
  38. package/src/components/List/index.tsx +114 -0
  39. package/src/components/List/styles.ts +19 -0
  40. package/src/components/Modal/index.tsx +218 -0
  41. package/src/components/Modal/styles.ts +153 -0
  42. package/src/components/MultiSelect/index.tsx +138 -0
  43. package/src/components/MultiSelect/styles.ts +18 -0
  44. package/src/components/MultiSelect/types.ts +42 -0
  45. package/src/components/Navigation/Navigation.tsx +54 -0
  46. package/src/components/Navigation/constants.ts +8 -0
  47. package/src/components/Navigation/index.tsx +3 -0
  48. package/src/components/Navigation/types.ts +35 -0
  49. package/src/components/Navigation/utils.tsx +57 -0
  50. package/src/components/Pager/index.tsx +121 -0
  51. package/src/components/Pager/styles.ts +81 -0
  52. package/src/components/RadioInput/index.tsx +106 -0
  53. package/src/components/RadioInput/styles.ts +67 -0
  54. package/src/components/Scroll/index.tsx +124 -0
  55. package/src/components/Scroll/styles.ts +18 -0
  56. package/src/components/Sections/index.tsx +91 -0
  57. package/src/components/SegmentedControl/index.tsx +204 -0
  58. package/src/components/SegmentedControl/styles.ts +89 -0
  59. package/src/components/Select/index.tsx +167 -0
  60. package/src/components/Select/styles.ts +62 -0
  61. package/src/components/Select/types.ts +43 -0
  62. package/src/components/Slider/Mark.tsx +46 -0
  63. package/src/components/Slider/Thumb.tsx +29 -0
  64. package/src/components/Slider/index.tsx +130 -0
  65. package/src/components/Slider/styles.ts +76 -0
  66. package/src/components/Slider/types.ts +30 -0
  67. package/src/components/Switch/index.tsx +91 -0
  68. package/src/components/Switch/styles.ts +38 -0
  69. package/src/components/Text/index.tsx +124 -0
  70. package/src/components/Text/styles.ts +50 -0
  71. package/src/components/TextInput/index.tsx +319 -0
  72. package/src/components/TextInput/styles.ts +127 -0
  73. package/src/components/Touchable/index.tsx +174 -0
  74. package/src/components/Touchable/styles.ts +28 -0
  75. package/src/components/View/index.tsx +103 -0
  76. package/src/components/View/styles.ts +24 -0
  77. package/src/components/components.ts +42 -0
  78. package/src/components/defaultStyles.ts +62 -0
  79. package/src/components/legacy/Modal/index.tsx +163 -0
  80. package/src/components/legacy/Modal/styles.ts +125 -0
  81. package/src/components/legacy/Pager/index.tsx +242 -0
  82. package/src/components/legacy/Pager/styles.ts +51 -0
  83. package/src/components/legacy/index.ts +2 -0
  84. package/src/modules/documentPicker.ts +7 -0
  85. package/src/modules/fastImage.ts +2 -0
  86. package/src/modules/imageCropPicker.d.ts +497 -0
  87. package/src/modules/index.d.ts +682 -0
  88. package/src/modules/reactNavigation.ts +15 -0
  89. package/src/modules/textInputMask.ts +11 -0
  90. package/src/modules/types/documentPicker.d.ts +215 -0
  91. package/src/modules/types/fileTypes.ts +138 -0
  92. package/src/modules/types/textInputMask.ts +9 -0
  93. package/src/types/index.ts +1 -0
  94. package/src/types/utility.ts +9 -0
  95. package/src/utils/KeyboardAware/context.tsx +75 -0
  96. package/src/utils/KeyboardAware/index.ts +17 -0
  97. package/src/utils/KeyboardAware/keyboardHooks.ts +124 -0
  98. package/src/utils/KeyboardAware/lib/KeyboardAwareFlatList.ts +4 -0
  99. package/src/utils/KeyboardAware/lib/KeyboardAwareHOC.tsx +618 -0
  100. package/src/utils/KeyboardAware/lib/KeyboardAwareInterface.ts +13 -0
  101. package/src/utils/KeyboardAware/lib/KeyboardAwareScrollView.ts +6 -0
  102. package/src/utils/KeyboardAware/lib/KeyboardAwareSectionList.ts +6 -0
  103. package/src/utils/KeyboardAware/types.ts +159 -0
  104. package/src/utils/ModalManager/components.tsx +112 -0
  105. package/src/utils/ModalManager/context.tsx +260 -0
  106. package/src/utils/ModalManager/index.ts +16 -0
  107. package/src/utils/OSAlert.ts +180 -0
  108. package/src/utils/PermissionManager/context.tsx +302 -0
  109. package/src/utils/PermissionManager/index.ts +20 -0
  110. package/src/utils/PermissionManager/types.ts +24 -0
  111. package/src/utils/hooks.ts +163 -0
  112. package/src/utils/index.ts +11 -0
  113. package/src/utils/input.ts +51 -0
  114. package/src/utils/misc.ts +83 -0
  115. package/src/utils/notifications.ts +206 -0
  116. package/src/utils/theme.ts +58 -0
@@ -0,0 +1,319 @@
1
+ import * as React from 'react'
2
+ import {
3
+ ComponentVariants,
4
+ FormTypes,
5
+ getNestedStylesByKey,
6
+ IconPlaceholder,
7
+
8
+ TypeGuards,
9
+
10
+ useBooleanToggle,
11
+ useDefaultComponentStyle,
12
+ useValidate,
13
+ } from '@codeleap/common'
14
+ import { ComponentPropsWithoutRef, forwardRef, useImperativeHandle, useRef, useState } from 'react'
15
+ import { Text, TextProps } from '../Text'
16
+ import { View, ViewProps } from '../View'
17
+ import { StylesOf } from '../../types'
18
+ import { NativeSyntheticEvent, StyleSheet, TextInput as NativeTextInput, TextInputChangeEventData } from 'react-native'
19
+ import { Touchable, TouchableProps } from '../Touchable'
20
+ import { MaskedTextInput, TextInputMaskProps } from '../../modules/textInputMask'
21
+ import { InputLabel } from '../InputLabel'
22
+
23
+ export * from './styles'
24
+
25
+ import {
26
+ InputIconComposition,
27
+ TextInputComposition,
28
+ TextInputStyles,
29
+ } from './styles'
30
+ import { ActionIcon, ActionIconParts, ActionIconProps } from '../ActionIcon'
31
+
32
+ type NativeProps = ComponentPropsWithoutRef<typeof NativeTextInput>
33
+
34
+ type SubtitleProps = {
35
+ errorProps: TextProps
36
+ styles: Record<'wrapper'|'error'|'subtitle', any>
37
+ }
38
+
39
+ export type TextInputProps =
40
+ Partial<TextInputMaskProps> &
41
+ ComponentVariants<typeof TextInputStyles> &
42
+ Omit<NativeProps, 'value'> &
43
+ {
44
+ multiline?: boolean
45
+ onChangeText?: (text: string) => void
46
+ disabled?: boolean
47
+ edited?: boolean
48
+ type?: string
49
+ label?: React.ReactNode
50
+ debugName: string
51
+ leftIcon?: Partial<ActionIconProps>
52
+ rightIcon?: Partial<ActionIconProps>
53
+ styles?: StylesOf<TextInputComposition>
54
+ validate?: FormTypes.ValidatorFunctionWithoutForm | string
55
+ value?: string
56
+ password?: boolean
57
+ visibilityToggle?: boolean
58
+ touchableWrapper?: boolean
59
+ subtitle?: string | ((props: SubtitleProps) => React.ReactElement)
60
+ onPress?: () => void
61
+ masking?: FormTypes.TextField['masking']
62
+ innerWrapperProps?: ViewProps
63
+ wrapperProps?: TouchableProps
64
+ onChangeMask?: TextInputMaskProps['onChangeText']
65
+ required?:boolean
66
+ }
67
+
68
+ export const TextInput = forwardRef<NativeTextInput, TextInputProps>((rawprops, inputRef) => {
69
+ const {
70
+ onChange,
71
+ value,
72
+ onChangeText,
73
+ disabled,
74
+ edited,
75
+ onFocus,
76
+ onBlur,
77
+ variants,
78
+ label,
79
+ wrapperProps,
80
+ leftIcon,
81
+ rightIcon,
82
+ styles,
83
+ validate,
84
+ password,
85
+ visibilityToggle,
86
+ innerWrapperProps,
87
+ masking,
88
+ subtitle = '',
89
+ onChangeMask,
90
+ debugName,
91
+ required = false,
92
+ ...props
93
+ } = rawprops
94
+
95
+ const [isFocused, setFocus] = useState(false)
96
+ const [editedState, setEdited] = useState(edited)
97
+
98
+ const input = useRef<any>(null)
99
+ const maskInputRef = useRef<any>(null)
100
+ const [textIsVisible, setTextVisible] = useBooleanToggle(false)
101
+ const variantStyles = useDefaultComponentStyle<'u:TextInput', typeof TextInputStyles>('u:TextInput', {
102
+ variants,
103
+ styles,
104
+ transform: StyleSheet.flatten,
105
+ })
106
+ const InputElement = masking ? MaskedTextInput : NativeTextInput
107
+
108
+ const handleBlur: TextInputProps['onBlur'] = (e) => {
109
+ if (!editedState && value) setEdited(true)
110
+ setFocus(false)
111
+
112
+ if (onBlur) {
113
+ onBlur(e)
114
+ }
115
+ }
116
+
117
+ const handleFocus: TextInputProps['onFocus'] = (e) => {
118
+ setFocus(true)
119
+ if (onFocus) {
120
+ onFocus(e)
121
+ }
122
+ }
123
+ const handleMaskChange = (masked, unmasked) => {
124
+
125
+ if (onChangeText) onChangeText(masking?.saveFormatted ? masked : masked)
126
+ if (onChangeMask) onChangeMask(masked, unmasked)
127
+ }
128
+ const handleChange = (event: NativeSyntheticEvent<TextInputChangeEventData>) => {
129
+ const text = event.nativeEvent.text
130
+
131
+ if (onChange) onChange(event)
132
+ if (onChangeText) onChangeText(text)
133
+ }
134
+
135
+ useImperativeHandle(inputRef, () => {
136
+ return {
137
+ ...input.current,
138
+ focus: () => {
139
+ input.current?.focus?.()
140
+ },
141
+ isTextInput: true,
142
+ }
143
+
144
+ }, [!!masking, !!input?.current?.focus])
145
+
146
+ const { showError, error } = useValidate(value, validate)
147
+
148
+ const commonIconStyles = getNestedStylesByKey('icon', variantStyles)
149
+
150
+ const leftIconStyles = getNestedStylesByKey('leftIcon', variantStyles)
151
+
152
+ const rightIconStyles = getNestedStylesByKey('rightIcon', variantStyles)
153
+
154
+ function getStyles(key: TextInputComposition) {
155
+ const requestedStyles = [
156
+ variantStyles[key],
157
+ isFocused ? variantStyles[key + ':focus'] : {},
158
+ showError ? variantStyles[key + ':error'] : {},
159
+ ]
160
+ return StyleSheet.flatten(requestedStyles)
161
+ }
162
+
163
+ function handlePress() {
164
+ if (props.onPress) {
165
+ props.onPress()
166
+ } else {
167
+ input.current?.focus?.()
168
+ }
169
+ }
170
+
171
+ const visibilityToggleProps = visibilityToggle ? {
172
+ onPress: () => setTextVisible(),
173
+ icon: (textIsVisible ? 'input-visiblity:visible' : 'input-visiblity:hidden') as IconPlaceholder,
174
+ debugName: `${debugName} toggle visibility`,
175
+ } : {}
176
+
177
+ const subtitleStyles = {
178
+ error: getStyles('error'),
179
+ wrapper: getStyles('subtitleWrapper'),
180
+ subtitle: getStyles('subtitle'),
181
+
182
+ }
183
+ const errorProps = { text: error.message, style: subtitleStyles.error }
184
+
185
+ const subtitleContent = TypeGuards.isFunction(subtitle) ? subtitle({ styles: subtitleStyles, errorProps }) : <View style={subtitleStyles.wrapper}>
186
+ <FormError {...errorProps}/>
187
+ {TypeGuards.isString(subtitle) ? <Text text={subtitle} style={subtitleStyles.subtitle}/> : (subtitle || null)}
188
+ </View>
189
+ return (
190
+ <Touchable
191
+ style={getStyles('wrapper')}
192
+ debugName={debugName}
193
+ onPress={handlePress}
194
+ {...wrapperProps}
195
+ android_ripple={null}
196
+ noFeedback
197
+ >
198
+ <InputLabel
199
+ label={label}
200
+ styles={{
201
+ wrapper: getStyles('labelWrapper'),
202
+ asterisk: getStyles('labelAsterisk'),
203
+ text: getStyles('labelText'),
204
+ }}
205
+ required={required}
206
+ />
207
+ <View style={getStyles('innerWrapper')} {...innerWrapperProps}>
208
+ <InputIcon
209
+ isFocused={isFocused}
210
+ showError={showError}
211
+ styles={leftIconStyles}
212
+ commonStyles={commonIconStyles}
213
+ debugName={`${debugName} left icon`}
214
+ onPress={() => {}}
215
+ noFeedback={!leftIcon?.onPress}
216
+ {...leftIcon}
217
+ />
218
+ {/* @ts-ignore */}
219
+ <InputElement
220
+
221
+ secureTextEntry={password && !textIsVisible}
222
+ onChange={(e) => masking ? onChange?.(e) : handleChange(e)}
223
+ value={value}
224
+ editable={disabled}
225
+ onFocus={handleFocus}
226
+ onBlur={handleBlur}
227
+ placeholderTextColor={StyleSheet.flatten(getStyles('placeholder'))?.color}
228
+ selectionColor={StyleSheet.flatten(getStyles('selection'))?.color}
229
+ includeRawValueInChangeText={true}
230
+ {...props}
231
+ {...masking}
232
+ {...(!!masking ? {
233
+ onChangeText: handleMaskChange,
234
+ ref: maskInputRef,
235
+ refInput: (inputRef) => {
236
+ // console.log(inputRef)
237
+ if (!!inputRef) {
238
+ input.current = inputRef
239
+
240
+ }
241
+ },
242
+ ...masking,
243
+ } : {
244
+ ref: input,
245
+ })}
246
+ style={getStyles('textField')}
247
+ />
248
+ <InputIcon
249
+ isFocused={isFocused}
250
+ showError={showError}
251
+ styles={rightIconStyles}
252
+ commonStyles={commonIconStyles}
253
+ debugName={`${debugName} right icon`}
254
+ onPress={() => {}}
255
+ noFeedback={!rightIcon?.onPress}
256
+ {...rightIcon}
257
+ {...visibilityToggleProps}
258
+ />
259
+
260
+ </View>
261
+ {subtitleContent}
262
+ </Touchable>
263
+ )
264
+ })
265
+
266
+ export const FormError:React.FC<TextProps> = ({ text, ...props }) => {
267
+ let message = text
268
+ if (TypeGuards.isNumber(message)) {
269
+ message = message.toString()
270
+ }
271
+ if (typeof message === 'undefined') {
272
+ message = ''
273
+ }
274
+
275
+ if (TypeGuards.isString(message)) {
276
+ const text = message ? `${message.charAt(0).toUpperCase() + message.slice(1)}` : ' '
277
+ return <Text text={text} {...props} />
278
+ }
279
+ return <>
280
+ {text}
281
+ </>
282
+ }
283
+
284
+ type InputIconProps = {
285
+ styles: StylesOf<InputIconComposition>
286
+ commonStyles: StylesOf<InputIconComposition>
287
+ isFocused: boolean
288
+ showError: boolean
289
+ } & Omit<ActionIconProps, 'styles'>
290
+
291
+ export const InputIcon:React.FC<InputIconProps> = ({ styles, commonStyles, isFocused, showError, ...props }) => {
292
+ if (!props.icon) return null
293
+
294
+ function getStyles(k: ActionIconParts | '') {
295
+ let key = k
296
+ if (key === 'icon') key = ''
297
+ const requestedStyles = [
298
+ commonStyles[key],
299
+ isFocused ? commonStyles[key + ':focus'] : {},
300
+ showError ? commonStyles[key + ':error'] : {},
301
+ styles[key],
302
+ isFocused ? styles[key + ':focus'] : {},
303
+ showError ? styles[key + ':error'] : {},
304
+ ]
305
+
306
+ return StyleSheet.flatten(requestedStyles)
307
+ }
308
+ const iconStyles = {
309
+ icon: getStyles('icon'),
310
+ touchablePressable: getStyles('touchablePressable'),
311
+ touchableWrapper: getStyles('touchableWrapper'),
312
+ touchableFeedback: getStyles('touchableFeedback'),
313
+ }
314
+
315
+ return <ActionIcon
316
+ styles={iconStyles}
317
+ {...props}
318
+ />
319
+ }
@@ -0,0 +1,127 @@
1
+ import { assignTextStyle, createDefaultVariantFactory, includePresets } from '@codeleap/common'
2
+ import { ActionIconParts } from '../ActionIcon'
3
+ import { InputLabelComposition } from '../InputLabel'
4
+
5
+ export type IconParts = Exclude<ActionIconParts, 'icon' | 'icon:disabled'>
6
+ type InputIcons = 'icon' | 'leftIcon' | 'rightIcon'
7
+
8
+ export type InputIconComposition = `${InputIcons}${Capitalize<IconParts>}`
9
+ | InputIcons
10
+
11
+ type TextInputParts =
12
+ | 'wrapper'
13
+ | InputIconComposition
14
+ | 'textField'
15
+ | 'innerWrapper'
16
+ | 'error'
17
+ | 'subtitle'
18
+ | 'subtitleWrapper'
19
+ | 'placeholder'
20
+ | 'selection'
21
+ | `label${Capitalize<InputLabelComposition>}`
22
+
23
+ export type TextInputComposition =
24
+ | `${TextInputParts}:error`
25
+ | `${TextInputParts}:focus`
26
+ | TextInputParts
27
+
28
+ const createTextInputStyle =
29
+ createDefaultVariantFactory<TextInputComposition>()
30
+
31
+ const presets = includePresets((styles) => createTextInputStyle(() => ({ wrapper: styles })))
32
+
33
+ export const TextInputStyles = {
34
+ ...presets,
35
+ default: createTextInputStyle((theme) => ({
36
+ textField: {
37
+ ...theme.spacing.padding(0),
38
+ ...theme.spacing.paddingHorizontal(1),
39
+ ...assignTextStyle('p1')(theme).text,
40
+ minWidth: 1,
41
+ backgroundColor: 'transparent',
42
+ flex: 1,
43
+ },
44
+ placeholder: {
45
+ color: theme.colors.lightGray,
46
+ },
47
+ selection: {
48
+ color: theme.colors.primary,
49
+ },
50
+ wrapper: {
51
+ display: 'flex',
52
+ flexDirection: 'column',
53
+
54
+ },
55
+ innerWrapper: {
56
+ ...theme.spacing.paddingVertical(0.5),
57
+ ...theme.spacing.paddingHorizontal(1),
58
+ ...theme.presets.row,
59
+ ...theme.border.neutral(1),
60
+ display: 'flex',
61
+ alignItems: 'center',
62
+ },
63
+
64
+ labelWrapper: {
65
+ ...theme.spacing.marginBottom(1),
66
+
67
+ },
68
+ labelText: {
69
+ ...assignTextStyle('h5')(theme).text,
70
+ },
71
+ 'icon': {
72
+ color: theme.colors.neutral,
73
+ },
74
+ 'icon:error': {
75
+ color: theme.colors.negative,
76
+ },
77
+ 'icon:focus': {
78
+ color: theme.colors.primary,
79
+ },
80
+ leftIconTouchableWrapper: {
81
+ // ...theme.spacing.marginRight(0.5),
82
+ },
83
+ rightIconTouchableWrapper: {
84
+ // ...theme.spacing.marginLeft(0.5),
85
+ },
86
+ error: {
87
+ color: theme.colors.negative,
88
+
89
+ },
90
+ subtitleWrapper: {
91
+ ...theme.spacing.marginTop(0.2),
92
+ ...theme.presets.row,
93
+ ...theme.presets.justifySpaceBetween,
94
+ ...theme.presets.alignCenter,
95
+ },
96
+ subtitle: {
97
+ ...theme.presets.textRight,
98
+ },
99
+ 'labelText:error': {
100
+ color: theme.colors.negative,
101
+ },
102
+
103
+ 'innerWrapper:error': {
104
+ ...theme.border.negative(1),
105
+ },
106
+ 'innerWrapper:focus': {
107
+ ...theme.border.primary(1),
108
+ },
109
+
110
+ })),
111
+ line: createTextInputStyle((theme) => ({
112
+ innerWrapper: {
113
+ ...theme.border.neutral({ width: 1, directions: ['bottom'] }),
114
+ },
115
+ })),
116
+ box: createTextInputStyle((theme) => ({
117
+ innerWrapper: {
118
+ ...theme.border.neutral(1),
119
+ },
120
+ })),
121
+ pill: createTextInputStyle((theme) => ({
122
+ innerWrapper: {
123
+ ...theme.border.neutral(1),
124
+ borderRadius: 15,
125
+ },
126
+ })),
127
+ }
@@ -0,0 +1,174 @@
1
+ import * as React from 'react'
2
+ import { ComponentPropsWithoutRef, forwardRef } from 'react'
3
+ import {
4
+ ComponentVariants,
5
+ useDefaultComponentStyle,
6
+ BaseViewProps,
7
+
8
+ useCodeleapContext,
9
+ AnyFunction,
10
+ TypeGuards,
11
+ } from '@codeleap/common'
12
+ import { Pressable, StyleSheet, View as RNView } from 'react-native'
13
+
14
+ import { createAnimatableComponent } from 'react-native-animatable'
15
+ import { TouchableComposition, TouchableStyles } from './styles'
16
+ import { StylesOf } from '../../types'
17
+ import { View } from '../View'
18
+ import { usePressableFeedback } from '../../utils'
19
+ export type TouchableProps = Omit<
20
+ ComponentPropsWithoutRef<typeof Pressable>,
21
+ 'onPress'
22
+ > & {
23
+ variants?: ComponentVariants<typeof TouchableStyles>['variants']
24
+ component?: any
25
+ ref?: React.Ref<RNView>
26
+ debugName: string
27
+ activeOpacity?: number
28
+ debugComponent?: string
29
+ onPress?: AnyFunction
30
+ noFeedback?: boolean
31
+ debounce?: number
32
+ styles?: StylesOf<TouchableComposition>
33
+ } & BaseViewProps
34
+ export * from './styles'
35
+
36
+ export const Touchable: React.FC<TouchableProps> = forwardRef<
37
+ RNView,
38
+ TouchableProps
39
+ >((touchableProps, ref) => {
40
+ const {
41
+ variants = [],
42
+ children,
43
+ onPress,
44
+ style,
45
+ debugName,
46
+ debugComponent,
47
+ debounce = 1000,
48
+ noFeedback = false,
49
+ styles,
50
+ ...props
51
+ } = touchableProps
52
+ const pressed = React.useRef(false)
53
+ const variantStyles = useDefaultComponentStyle<'u:Touchable', typeof TouchableStyles>('u:Touchable', {
54
+ variants,
55
+ transform: StyleSheet.flatten,
56
+ rootElement: 'wrapper',
57
+ styles,
58
+ })
59
+
60
+ const { logger } = useCodeleapContext()
61
+
62
+ const press = () => {
63
+ if (!onPress) {
64
+ logger.warn('No onPress passed to touchable', {
65
+ touchableProps,
66
+ }, 'User Interaction')
67
+ return
68
+ }
69
+ const _onPress = () => {
70
+ logger.log(
71
+ `<${debugComponent || 'Touchable'}/> pressed`,
72
+ debugName || variants,
73
+ 'User interaction',
74
+ )
75
+ onPress && onPress()
76
+ }
77
+ if (TypeGuards.isNumber(debounce)) {
78
+ if (pressed.current) {
79
+ return
80
+ }
81
+ pressed.current = true
82
+ _onPress()
83
+ setTimeout(() => {
84
+ pressed.current = false
85
+ }, debounce)
86
+ } else {
87
+ _onPress()
88
+ }
89
+
90
+ }
91
+
92
+ const _styles = StyleSheet.flatten([variantStyles.wrapper, style])
93
+
94
+ const disableFeedback = !onPress || noFeedback
95
+
96
+ const { rippleConfig, getFeedbackStyle } = usePressableFeedback(_styles, {
97
+ hightlightPropertyIn: 'backgroundColor',
98
+ hightlightPropertyOut: 'backgroundColor',
99
+ disabled: disableFeedback,
100
+ feedbackConfig: variantStyles?.feedback,
101
+ })
102
+
103
+ const Wrapper = View
104
+
105
+ const { wrapperStyle, pressableStyle } = React.useMemo(() => {
106
+ const wrapperkeys = [
107
+ 'margin',
108
+ 'alignSelf',
109
+ 'border',
110
+ 'top!',
111
+ 'left!',
112
+ 'right!',
113
+ 'bottom!',
114
+ 'position!',
115
+ // 'flex!',
116
+ ]
117
+ const sharedKeys = [
118
+ 'width!',
119
+ 'height!',
120
+ 'flex!',
121
+ 'backgroundColor!',
122
+
123
+ ]
124
+
125
+ const wrapperStyle = {} as any
126
+ const pressableStyle = {} as any
127
+ const match = (k, key) => {
128
+ if (k.endsWith('!')) {
129
+ return key === k.substring(0, k.length - 1)
130
+ } else {
131
+
132
+ return key.startsWith(k)
133
+ }
134
+ }
135
+ Object.entries(_styles).forEach(([key, value]) => {
136
+
137
+ if (wrapperkeys.some(k => match(k, key))) {
138
+ wrapperStyle[key] = value
139
+ } else if (sharedKeys.some(k => match(k, key))) {
140
+ wrapperStyle[key] = value
141
+
142
+ pressableStyle[key] = value
143
+ } else {
144
+ pressableStyle[key] = value
145
+ }
146
+ })
147
+
148
+ wrapperStyle.overflow = 'hidden'
149
+ // wrapperStyle.flexDirection = 'row'
150
+ // wrapperStyle.alignItems = 'stretch'
151
+
152
+ return {
153
+ wrapperStyle,
154
+ pressableStyle,
155
+ }
156
+ }, [JSON.stringify(_styles)])
157
+
158
+ return (
159
+ <Wrapper style={[wrapperStyle]}>
160
+ <Pressable onPress={press} style={({ pressed }) => ([
161
+
162
+ // defaultPressableStyles,
163
+ pressableStyle,
164
+ // !!rippleConfig && ripplePressableStyles,
165
+ getFeedbackStyle(pressed),
166
+ variantStyles.pressable,
167
+ ])} android_ripple={rippleConfig} {...props} ref={ref}>
168
+ {children}
169
+ </Pressable>
170
+ </Wrapper>
171
+ )
172
+ })
173
+
174
+ export const AnimatedTouchable = createAnimatableComponent(Touchable) as unknown as typeof Touchable
@@ -0,0 +1,28 @@
1
+ import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
2
+ import { StylesOf } from '../../types'
3
+ import { TouchableFeedbackConfig } from '../../utils'
4
+
5
+ export type TouchableComposition = 'wrapper' | 'feedback' | 'pressable'
6
+
7
+ export type TouchableStylesGen<TCSS = any> = StylesOf<Exclude<TouchableComposition, 'feedback'>> & {
8
+ feedback?: TouchableFeedbackConfig
9
+ }
10
+
11
+ const createTouchableStyle = createDefaultVariantFactory<
12
+ TouchableComposition,
13
+ TouchableStylesGen
14
+ >()
15
+
16
+ const presets = includePresets((styles) => createTouchableStyle(() => ({ wrapper: styles, pressable: styles })),
17
+ )
18
+
19
+ export const TouchableStyles = {
20
+ ...presets,
21
+ default: createTouchableStyle((t) => ({
22
+ feedback: {
23
+ type: 'opacity',
24
+ value: 0.5,
25
+ },
26
+ })),
27
+
28
+ }