@codeleap/mobile 2.0.1 → 2.0.2

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 (105) hide show
  1. package/dist/components/ActionIcon/styles.d.ts +58 -58
  2. package/dist/components/Backdrop/index.js +1 -1
  3. package/dist/components/Backdrop/index.js.map +1 -1
  4. package/dist/components/Button/index.d.ts +109 -109
  5. package/dist/components/Button/index.js +5 -7
  6. package/dist/components/Button/index.js.map +1 -1
  7. package/dist/components/Button/styles.d.ts +60 -55
  8. package/dist/components/Button/styles.js +4 -2
  9. package/dist/components/Button/styles.js.map +1 -1
  10. package/dist/components/Checkbox/index.js +4 -2
  11. package/dist/components/Checkbox/index.js.map +1 -1
  12. package/dist/components/Checkbox/styles.d.ts +1 -1
  13. package/dist/components/Checkbox/styles.js +4 -0
  14. package/dist/components/Checkbox/styles.js.map +1 -1
  15. package/dist/components/FileInput/index.d.ts +1 -1
  16. package/dist/components/Image/index.js +3 -0
  17. package/dist/components/Image/index.js.map +1 -1
  18. package/dist/components/Modal/index.js +1 -1
  19. package/dist/components/Modal/index.js.map +1 -1
  20. package/dist/components/MultiSelect/styles.js +1 -4
  21. package/dist/components/MultiSelect/styles.js.map +1 -1
  22. package/dist/components/Navigation/utils.js +0 -1
  23. package/dist/components/Navigation/utils.js.map +1 -1
  24. package/dist/components/Pager/styles.js +13 -11
  25. package/dist/components/Pager/styles.js.map +1 -1
  26. package/dist/components/RadioInput/index.js +3 -1
  27. package/dist/components/RadioInput/index.js.map +1 -1
  28. package/dist/components/RadioInput/styles.d.ts +1 -1
  29. package/dist/components/RadioInput/styles.js +1 -0
  30. package/dist/components/RadioInput/styles.js.map +1 -1
  31. package/dist/components/SegmentedControl/index.d.ts +10 -1
  32. package/dist/components/SegmentedControl/index.js +27 -27
  33. package/dist/components/SegmentedControl/index.js.map +1 -1
  34. package/dist/components/SegmentedControl/styles.d.ts +56 -51
  35. package/dist/components/SegmentedControl/styles.js +10 -3
  36. package/dist/components/SegmentedControl/styles.js.map +1 -1
  37. package/dist/components/Select/index.js +1 -2
  38. package/dist/components/Select/index.js.map +1 -1
  39. package/dist/components/Select/styles.d.ts +1 -1
  40. package/dist/components/Select/styles.js +4 -1
  41. package/dist/components/Select/styles.js.map +1 -1
  42. package/dist/components/Switch/index.js +1 -1
  43. package/dist/components/Switch/index.js.map +1 -1
  44. package/dist/components/Text/index.d.ts +2 -0
  45. package/dist/components/Text/index.js +46 -2
  46. package/dist/components/Text/index.js.map +1 -1
  47. package/dist/components/Text/styles.d.ts +57 -52
  48. package/dist/components/Text/styles.js +11 -3
  49. package/dist/components/Text/styles.js.map +1 -1
  50. package/dist/components/TextInput/index.d.ts +8 -4
  51. package/dist/components/TextInput/index.js +35 -15
  52. package/dist/components/TextInput/index.js.map +1 -1
  53. package/dist/components/TextInput/styles.d.ts +1 -1
  54. package/dist/components/TextInput/styles.js +11 -3
  55. package/dist/components/TextInput/styles.js.map +1 -1
  56. package/dist/components/Touchable/index.d.ts +1 -1
  57. package/dist/components/Touchable/index.js +77 -42
  58. package/dist/components/Touchable/index.js.map +1 -1
  59. package/dist/components/Touchable/styles.d.ts +56 -51
  60. package/dist/components/Touchable/styles.js +6 -1
  61. package/dist/components/Touchable/styles.js.map +1 -1
  62. package/dist/components/defaultStyles.d.ts +263 -263
  63. package/dist/utils/KeyboardAware/lib/KeyboardAwareHOC.d.ts +2 -0
  64. package/dist/utils/KeyboardAware/lib/KeyboardAwareHOC.js +287 -286
  65. package/dist/utils/KeyboardAware/lib/KeyboardAwareHOC.js.map +1 -1
  66. package/dist/utils/OSAlert.d.ts +6 -5
  67. package/dist/utils/OSAlert.js +7 -6
  68. package/dist/utils/OSAlert.js.map +1 -1
  69. package/dist/utils/hooks.d.ts +34 -1
  70. package/dist/utils/hooks.js +54 -1
  71. package/dist/utils/hooks.js.map +1 -1
  72. package/dist/utils/index.d.ts +1 -1
  73. package/dist/utils/index.js +2 -6
  74. package/dist/utils/index.js.map +1 -1
  75. package/dist/utils/notifications.js +4 -4
  76. package/dist/utils/notifications.js.map +1 -1
  77. package/package.json +1 -1
  78. package/src/components/Backdrop/index.tsx +1 -1
  79. package/src/components/Button/index.tsx +7 -11
  80. package/src/components/Button/styles.ts +34 -10
  81. package/src/components/Checkbox/index.tsx +4 -1
  82. package/src/components/Checkbox/styles.ts +5 -0
  83. package/src/components/Image/index.tsx +3 -0
  84. package/src/components/Modal/index.tsx +1 -1
  85. package/src/components/MultiSelect/styles.ts +1 -8
  86. package/src/components/Navigation/utils.tsx +0 -2
  87. package/src/components/Pager/styles.ts +16 -11
  88. package/src/components/RadioInput/index.tsx +3 -1
  89. package/src/components/RadioInput/styles.ts +2 -1
  90. package/src/components/SegmentedControl/index.tsx +31 -18
  91. package/src/components/SegmentedControl/styles.ts +29 -7
  92. package/src/components/Select/index.tsx +2 -1
  93. package/src/components/Select/styles.ts +12 -2
  94. package/src/components/Switch/index.tsx +1 -1
  95. package/src/components/Text/index.tsx +60 -5
  96. package/src/components/Text/styles.ts +25 -9
  97. package/src/components/TextInput/index.tsx +44 -9
  98. package/src/components/TextInput/styles.ts +14 -4
  99. package/src/components/Touchable/index.tsx +84 -35
  100. package/src/components/Touchable/styles.ts +15 -3
  101. package/src/utils/KeyboardAware/lib/KeyboardAwareHOC.tsx +34 -24
  102. package/src/utils/OSAlert.ts +10 -10
  103. package/src/utils/hooks.ts +82 -2
  104. package/src/utils/index.ts +2 -2
  105. package/src/utils/notifications.ts +4 -4
@@ -51,17 +51,22 @@ export function pagerAnimation(height, width, translate = 'X', transition = defa
51
51
 
52
52
  export const PagerStyles = {
53
53
  ...presets,
54
- default: createPagerStyle((theme) => ({
55
- page: {
56
- width: '100%',
57
- height: '100%',
58
- position: 'absolute',
59
- left: 0,
60
- right: 0,
61
- bottom: 0,
62
- top: 0,
63
- },
64
- })),
54
+ default: createPagerStyle((theme) => {
55
+ const width = theme.values.width
56
+ const height = theme.values.height * 0.8
57
+ return {
58
+ ...pagerAnimation(height, width, 'X'),
59
+ page: {
60
+ width: '100%',
61
+ height: '100%',
62
+ position: 'absolute',
63
+ left: 0,
64
+ right: 0,
65
+ bottom: 0,
66
+ top: 0,
67
+ },
68
+ }
69
+ }),
65
70
  horizontal: createPagerStyle((Theme) => {
66
71
 
67
72
  const width = Theme.values.width
@@ -47,7 +47,9 @@ export const RadioButton: React.FC<RadioButtonProps> = ({
47
47
  ...props
48
48
  }) => {
49
49
  return (
50
- <Touchable onPress={select} style={style.itemWrapper} debugName={'Change radioButton value'}>
50
+ <Touchable onPress={select} style={style.itemWrapper} debugName={'Change radioButton value'} styles={{
51
+ feedback: style.buttonFeedback,
52
+ }}>
51
53
  <View style={[style.button, checked && style['button:checked']]}>
52
54
  <View
53
55
  style={[style.buttonMark, checked && style['buttonMark:checked']]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createDefaultVariantFactory, includePresets,
3
3
  } from '@codeleap/common'
4
- type RadioParts = 'button' | 'itemWrapper' | 'text' | 'buttonMark'
4
+ type RadioParts = 'button' | 'itemWrapper' | 'text' | 'buttonMark' | 'buttonFeedback'
5
5
 
6
6
  type RadioGroupParts = 'label' | 'wrapper' | 'list'
7
7
 
@@ -37,6 +37,7 @@ export const RadioInputStyles = {
37
37
  position: 'relative',
38
38
  ...theme.spacing.marginRight(1),
39
39
  },
40
+ buttonFeedback: { type: 'opacity', value: 0.5 },
40
41
  buttonMark: {
41
42
  backgroundColor: theme.colors.primary,
42
43
  position: 'absolute',
@@ -1,12 +1,12 @@
1
1
  import React, { ReactElement, useImperativeHandle, useMemo, useRef } from 'react'
2
2
  import { Scroll, ScrollProps } from '../Scroll'
3
3
 
4
- import { EasingFunction, StyleSheet } from 'react-native'
4
+ import { Easing, EasingFunction, StyleSheet } from 'react-native'
5
5
  import { PropsOf, useCodeleapContext, useDefaultComponentStyle } from '@codeleap/common'
6
6
  import { SegmentedControlComposition, SegmentedControlStyles } from './styles'
7
7
  import { Touchable } from '../Touchable'
8
8
  import { StylesOf } from '../../types/utility'
9
- import { Text } from '../Text'
9
+ import { Text, TextProps } from '../Text'
10
10
  import { KeyboardAwareScrollViewTypes } from '../../modules'
11
11
  import { View } from '../View'
12
12
  export * from './styles'
@@ -24,6 +24,8 @@ export type SegmentedControlProps<T = string> = ScrollProps & {
24
24
  duration?: number
25
25
  easing?: EasingFunction
26
26
  }
27
+ textProps?: Partial<PropsOf<typeof Text>>
28
+ touchableProps?: Partial<PropsOf<typeof Touchable>>
27
29
  styles?: StylesOf<SegmentedControlComposition>
28
30
  scrollProps?: any
29
31
  RenderButton?: (props: SegmentedControlProps & {
@@ -31,12 +33,14 @@ export type SegmentedControlProps<T = string> = ScrollProps & {
31
33
  textProps: PropsOf<typeof Text>
32
34
  option: {label: string; value: any}
33
35
  }) => ReactElement
34
- RenderAnimatedView?: (props: SegmentedControlProps) => ReactElement
36
+ RenderAnimatedView?: (props: Partial<SegmentedControlProps>) => ReactElement
37
+ getItemWidth?: (item:{label: string; value: T }, idx: number, arr: {label: string; value: T }[]) => number
35
38
  }
36
39
 
37
40
  const defaultAnimation = {
41
+ type: 'timing',
38
42
  duration: 200,
39
- // easing: Easing.linear,
43
+ easing: Easing.linear,
40
44
  }
41
45
 
42
46
  const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControlProps>((props, ref) => {
@@ -49,13 +53,13 @@ const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControl
49
53
  animation = {},
50
54
  variants = [],
51
55
  scrollProps = {},
56
+ getItemWidth = (i) => i.label.length * 20,
52
57
  RenderAnimatedView,
53
58
  RenderButton,
54
-
59
+ ...viewProps
55
60
  } = props
56
- const { Theme } = useCodeleapContext()
57
61
 
58
- const _animation = {
62
+ let _animation = {
59
63
  ...defaultAnimation, ...animation,
60
64
  }
61
65
 
@@ -75,14 +79,10 @@ const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControl
75
79
  }
76
80
 
77
81
  const widthStyle = useMemo(() => {
78
- const maxWordLength = Object.assign([], options)
79
- .sort((a, b) => {
80
- return a.label.length - b.label.length
81
- })[0].label.length
82
- const fitMaxWidth = Theme.values.width - Theme.spacing.value(4)
83
- let fitItemWidth = maxWordLength * options.length * 6
84
- if (fitItemWidth * options.length < fitMaxWidth) fitItemWidth = fitMaxWidth / options.length
85
- return { width: fitItemWidth }
82
+ const sizes = options.map(getItemWidth)
83
+ const maxWidth = sizes.sort((a, b) => b - a)[0]
84
+
85
+ return { width: maxWidth }
86
86
  }, [options])
87
87
 
88
88
  const currentOptionIdx = options.findIndex(o => o.value === value) || 0
@@ -118,6 +118,7 @@ const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControl
118
118
 
119
119
  const AnimatedView = RenderAnimatedView || View
120
120
  variantStyles = JSON.parse(JSON.stringify(variantStyles))
121
+ _animation = JSON.parse(JSON.stringify(_animation))
121
122
  return (
122
123
  <Scroll
123
124
  horizontal
@@ -128,14 +129,19 @@ const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControl
128
129
  ref={scrollRef}
129
130
  >
130
131
  <View style={variantStyles.wrapper}>
131
- <AnimatedView {...props}
132
+ <AnimatedView
133
+ options={options}
134
+ styles={variantStyles}
135
+
132
136
  animated
133
137
  style={[variantStyles.selectedBubble, widthStyle]}
134
138
  animate={{
135
139
  translateX,
136
140
  }}
141
+ transition={{
142
+ translateX: _animation,
143
+ }}
137
144
 
138
- transition={_animation}
139
145
  />
140
146
  {options.map((o, idx) => {
141
147
  const selected = value === o.value
@@ -145,13 +151,16 @@ const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControl
145
151
  debugName: `Segmented Control ${debugName}, option ${o.label}`,
146
152
  onPress: onPress(o.value, idx),
147
153
  style: [widthStyle, variantStyles.button],
154
+ ...props.touchableProps,
155
+
148
156
  }
149
157
 
150
- const textProps = {
158
+ const textProps:TextProps = {
151
159
  text: o.label as string,
152
160
  colorChangeConfig: _animation,
153
161
  style: StyleSheet.flatten([variantStyles.text, selected && variantStyles['text:selected']]),
154
162
  animated: true,
163
+ ...props.textProps,
155
164
  }
156
165
 
157
166
  if (RenderButton) {
@@ -161,7 +170,11 @@ const _SegmentedControl = React.forwardRef<SegmentedControlRef, SegmentedControl
161
170
  }
162
171
  return <Touchable
163
172
  {...touchableProps}
173
+ noFeedback={selected}
164
174
  key={touchableProps.key}
175
+ styles={{
176
+ feedback: variantStyles.buttonFeedback,
177
+ }}
165
178
  >
166
179
  <Text
167
180
 
@@ -1,4 +1,5 @@
1
- import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
1
+ import { createDefaultVariantFactory, includePresets, StylesOf } from '@codeleap/common'
2
+ import { TouchableStylesGen } from '../Touchable'
2
3
 
3
4
  export type SegmentedControlStates = 'selected'
4
5
 
@@ -10,9 +11,20 @@ export type SegmentedControlComposition =
10
11
  'text' |
11
12
  `text:${SegmentedControlStates}` |
12
13
  'button' |
14
+ 'buttonFeedback' |
13
15
  `button:${SegmentedControlStates}`
14
16
 
15
- const createSegmentedControlStyle = createDefaultVariantFactory<SegmentedControlComposition>()
17
+ export type SegmentedControlStylesGen<TCSS = any> =
18
+ StylesOf<
19
+ Exclude<SegmentedControlComposition, 'buttonFeedback'>
20
+ > & {
21
+ buttonFeedback?: TouchableStylesGen['feedback']
22
+ }
23
+
24
+ const createSegmentedControlStyle = createDefaultVariantFactory<
25
+ SegmentedControlComposition,
26
+ SegmentedControlStylesGen
27
+ >()
16
28
 
17
29
  const presets = includePresets((style) => createSegmentedControlStyle(() => ({ scrollContent: style })))
18
30
 
@@ -21,7 +33,10 @@ export const SegmentedControlStyles = {
21
33
  default: createSegmentedControlStyle((theme) => {
22
34
 
23
35
  return {
24
-
36
+ buttonFeedback: {
37
+ type: 'opacity',
38
+ value: 0.5,
39
+ },
25
40
  text: {
26
41
  color: theme.colors.text,
27
42
  },
@@ -34,21 +49,28 @@ export const SegmentedControlStyles = {
34
49
  },
35
50
  scrollContent: {
36
51
  // borderRadius: Theme.borderRadius.large,
52
+ ...theme.presets.row,
37
53
  ...theme.spacing.paddingHorizontal(2),
54
+ ...theme.presets.alignStretch,
38
55
  },
39
56
  button: {
40
57
  backgroundColor: 'transparent',
41
58
  ...theme.presets.alignCenter,
42
- color: 'red',
43
- ...theme.spacing.padding(2),
44
59
  ...theme.presets.justifyCenter,
60
+
61
+ borderRadius: theme.borderRadius.large,
62
+ ...theme.spacing.padding(1),
63
+ minHeight: '100%',
64
+
45
65
  },
46
66
  selectedBubble: {
47
67
  position: 'absolute',
48
68
  zIndex: -1,
49
69
  ...theme.spacing.padding(2),
50
- maxHeight: 50,
51
- minHeight: 50,
70
+ // maxHeight: 50,
71
+ // minHeight: 50,
72
+ top: 0,
73
+ bottom: 0,
52
74
  borderRadius: theme.borderRadius.large,
53
75
  backgroundColor: theme.colors.primary,
54
76
  },
@@ -97,9 +97,10 @@ export const Select = <T extends string|number = string>(selectProps:CustomSelec
97
97
  }}
98
98
  editable={false}
99
99
  touchableWrapper
100
+ onPress={close}
100
101
  wrapperProps={{
101
102
  debugName: 'Select',
102
- onPress: close,
103
+
103
104
  }}
104
105
  pointerEvents={'none'}
105
106
  label={label}
@@ -9,7 +9,8 @@ export type SelectComposition =
9
9
  `itemWrapper${ItemStates}` |
10
10
  `itemText${ItemStates}` |
11
11
  'scroll' |
12
- 'scrollContent'
12
+ 'scrollContent' |
13
+ `itemIcon${ItemStates}`
13
14
 
14
15
  const createSelectStyle = createDefaultVariantFactory<SelectComposition>()
15
16
 
@@ -24,10 +25,11 @@ export const SelectStyles = {
24
25
 
25
26
  },
26
27
  itemWrapper: {
27
- ...theme.spacing.padding(2),
28
28
  ...theme.presets.row,
29
29
  ...theme.presets.justifySpaceBetween,
30
30
  ...theme.presets.alignCenter,
31
+ ...theme.spacing.padding(1.4),
32
+ height: 50,
31
33
  },
32
34
  'itemWrapper:selected': {
33
35
  backgroundColor: theme.colors.primary,
@@ -36,6 +38,14 @@ export const SelectStyles = {
36
38
  color: theme.colors.white,
37
39
 
38
40
  },
41
+ 'itemIcon:selected': {
42
+ color: theme.colors.white,
43
+ ...theme.sized(3),
44
+ },
45
+ itemIcon: {
46
+ width: 0,
47
+ height: 0,
48
+ },
39
49
  list: {
40
50
  height: 'auto',
41
51
 
@@ -79,7 +79,7 @@ export const Switch = forwardRef<NativeSwitch, SwitchProps>(
79
79
  />
80
80
  <InputLabel label={label} style={getStyles('label')} />
81
81
  </View>
82
- <FormError message={error.message} style={getStyles('error')} />
82
+ <FormError text={error.message} style={getStyles('error')} />
83
83
  </View>
84
84
  )
85
85
  },
@@ -4,12 +4,14 @@ import {
4
4
  ComponentVariants,
5
5
  useDefaultComponentStyle,
6
6
  BaseViewProps,
7
-
7
+ TypeGuards,
8
+ useState,
8
9
  } from '@codeleap/common'
9
- import { Animated, StyleSheet, Text as NativeText } from 'react-native'
10
+ import { Animated, GestureResponderEvent, Platform, StyleSheet, Text as NativeText } from 'react-native'
10
11
  import { MotiText as _MotiText, MotiProps } from 'moti'
11
- import { useAnimateColor } from '../../utils'
12
+ import { useAnimateColor, usePressableFeedback } from '../../utils'
12
13
  import { TextStyles } from './styles'
14
+ import { View } from '../View'
13
15
 
14
16
  export * from './styles'
15
17
 
@@ -18,6 +20,7 @@ export type TextProps = ComponentPropsWithoutRef<typeof NativeText> & {
18
20
  variants?: ComponentVariants<typeof TextStyles>['variants']
19
21
  animated?: boolean
20
22
  colorChangeConfig?: Partial<Animated.TimingAnimationConfig>
23
+ debugName?: string
21
24
  } & BaseViewProps & MotiProps
22
25
 
23
26
  const MotiText = Animated.createAnimatedComponent(_MotiText)
@@ -25,8 +28,21 @@ const MotiText = Animated.createAnimatedComponent(_MotiText)
25
28
  export const Text = forwardRef<NativeText, TextProps>((textProps, ref) => {
26
29
  const { variants = [], text, children, style, colorChangeConfig, ...props } = textProps
27
30
 
28
- const variantStyles = useDefaultComponentStyle('Text', {
31
+ const pressPolyfillEnabled = Platform.OS === 'android' && !!props.onPress
32
+
33
+ const [pressed, setPressed] = useState(false)
34
+ const handlePress = (pressed) => {
35
+ if (!pressPolyfillEnabled) return
36
+ return () => {
37
+ if (props.onPress) {
38
+ setPressed(pressed)
39
+
40
+ }
41
+ }
42
+ }
43
+ const variantStyles = useDefaultComponentStyle<'u:Text', typeof TextStyles>('u:Text', {
29
44
  variants,
45
+ transform: StyleSheet.flatten,
30
46
  rootElement: 'text',
31
47
  })
32
48
 
@@ -34,14 +50,53 @@ export const Text = forwardRef<NativeText, TextProps>((textProps, ref) => {
34
50
 
35
51
  const animatedColor = useAnimateColor(styles.color, colorChangeConfig)
36
52
 
53
+ if (!!text && !TypeGuards.isString(text)) return <>{text}</>
54
+
37
55
  const Component = textProps.animated ? MotiText : NativeText
38
56
 
39
57
  const colorStyle = { color: props.animated ? animatedColor : styles.color }
40
58
 
59
+ const { getFeedbackStyle } = usePressableFeedback(styles, {
60
+ disabled: !pressPolyfillEnabled,
61
+ feedbackConfig: variantStyles.pressFeedback,
62
+ hightlightPropertyIn: 'color',
63
+ hightlightPropertyOut: 'backgroundColor',
64
+ })
65
+ const feedbackStyle = pressPolyfillEnabled ? getFeedbackStyle(pressed) : undefined
66
+
67
+ return <Component {...props}
68
+ onPressIn={handlePress(true)} onPressOut={handlePress(false)}
69
+ style={[styles, colorStyle, feedbackStyle]}
70
+ // @ts-ignore
71
+ ref={ref}
72
+ >
73
+ {text}
74
+ </Component>
75
+
41
76
  // @ts-ignore
42
77
  return <Component {...props} style={[styles, colorStyle]} ref={ref}>
43
- {text || children}
78
+ {text}
79
+ {children}
44
80
  </Component>
45
81
 
46
82
  })
47
83
 
84
+ // const childArr = React.Children.toArray([
85
+ // text,
86
+ // children,
87
+ // ])
88
+
89
+ // return <View style={[styles, colorStyle]}>
90
+ // {
91
+ // childArr.map((child) => {
92
+ // if (TypeGuards.isString(child)) {
93
+ // // @ts-ignore
94
+ // return <Component {...props} ref={ref}>
95
+ // {child}
96
+ // </Component>
97
+
98
+ // }
99
+ // return child
100
+ // })
101
+ // }
102
+ // </View>
@@ -1,19 +1,35 @@
1
- import { assignTextStyle, createDefaultVariantFactory, includePresets } from '@codeleap/common'
1
+ import { assignTextStyle, createDefaultVariantFactory, includePresets, shadeColor, StylesOf } from '@codeleap/common'
2
+ import { FeedbackConfig } from '../../utils'
2
3
 
3
- export type TextComposition = 'text'
4
- const createTextStyle = createDefaultVariantFactory<TextComposition>()
4
+ export type TextComposition = 'text' | 'touchFeedback'
5
+
6
+ export type TextStylesGen<TCSS = any> = StylesOf<'text', TCSS> & {
7
+ 'pressFeedback'?: FeedbackConfig
8
+ }
9
+
10
+ const createTextStyle = createDefaultVariantFactory<
11
+ TextComposition, TextStylesGen
12
+ >()
5
13
 
6
14
  const presets = includePresets((styles) => createTextStyle(() => ({ text: styles })),
7
15
  )
8
16
 
9
17
  export const TextStyles = {
10
18
  ...presets,
11
- default: createTextStyle((theme) => ({
12
- text: {
13
- fontFamily: theme.typography.fontFamily,
14
- ...assignTextStyle('p1')(theme).text,
15
- },
16
- })),
19
+ default: createTextStyle((theme) => {
20
+ const defaultStyle = assignTextStyle('p1')(theme).text
21
+ return {
22
+ text: {
23
+ fontFamily: theme.typography.fontFamily,
24
+ ...defaultStyle,
25
+ },
26
+ pressFeedback: {
27
+ type: 'highlight',
28
+ brightness: 0,
29
+ shiftOpacity: 0.3,
30
+ },
31
+ }
32
+ }),
17
33
  h1: assignTextStyle('h1'),
18
34
  h2: assignTextStyle('h2'),
19
35
  h3: assignTextStyle('h3'),
@@ -5,12 +5,14 @@ import {
5
5
  getNestedStylesByKey,
6
6
  IconPlaceholder,
7
7
 
8
+ TypeGuards,
9
+
8
10
  useBooleanToggle,
9
11
  useDefaultComponentStyle,
10
12
  useValidate,
11
13
  } from '@codeleap/common'
12
14
  import { ComponentPropsWithoutRef, forwardRef, useImperativeHandle, useRef, useState } from 'react'
13
- import { Text } from '../Text'
15
+ import { Text, TextProps } from '../Text'
14
16
  import { View, ViewProps } from '../View'
15
17
  import { StylesOf } from '../../types'
16
18
  import { Icon } from '../Icon'
@@ -34,6 +36,11 @@ type IconProp = { name: IconPlaceholder; action?: () => void }
34
36
 
35
37
  type NativeProps = ComponentPropsWithoutRef<typeof NativeTextInput>
36
38
 
39
+ type SubtitleProps = {
40
+ errorProps: TextProps
41
+ styles: Record<'wrapper'|'error'|'subtitle', any>
42
+ }
43
+
37
44
  export type TextInputProps =
38
45
  Partial<TextInputMaskProps> &
39
46
  ComponentVariants<typeof TextInputStyles> &
@@ -54,6 +61,7 @@ export type TextInputProps =
54
61
  password?: boolean
55
62
  visibilityToggle?: boolean
56
63
  touchableWrapper?: boolean
64
+ subtitle?: string | ((props: SubtitleProps) => React.ReactElement)
57
65
  onPress?: () => void
58
66
  masking?: FormTypes.TextField['masking']
59
67
  innerWrapperProps?: ViewProps
@@ -82,6 +90,7 @@ export const TextInput = forwardRef<NativeTextInput, TextInputProps>((rawprops,
82
90
  visibilityToggle,
83
91
  innerWrapperProps,
84
92
  masking = null,
93
+ subtitle = '',
85
94
  onChangeMask,
86
95
  debugName,
87
96
  required = false,
@@ -144,7 +153,7 @@ export const TextInput = forwardRef<NativeTextInput, TextInputProps>((rawprops,
144
153
  isFocused ? variantStyles[key + ':focus'] : {},
145
154
  showError ? variantStyles[key + ':error'] : {},
146
155
  ]
147
- return requestedStyles
156
+ return StyleSheet.flatten(requestedStyles)
148
157
  }
149
158
 
150
159
  function handlePress() {
@@ -161,6 +170,19 @@ export const TextInput = forwardRef<NativeTextInput, TextInputProps>((rawprops,
161
170
  debugName: `${debugName} toggle visibility`,
162
171
  } : {}
163
172
 
173
+ const subtitleStyles = {
174
+ error: getStyles('error'),
175
+ wrapper: getStyles('subtitleWrapper'),
176
+ subtitle: getStyles('subtitle'),
177
+
178
+ }
179
+ const errorProps = { text: error.message, style: subtitleStyles.error }
180
+
181
+ const subtitleContent = TypeGuards.isFunction(subtitle) ? subtitle({ styles: subtitleStyles, errorProps }) : <View style={subtitleStyles.wrapper}>
182
+ <FormError {...errorProps}/>
183
+ {TypeGuards.isString(subtitle) ? <Text text={subtitle} style={subtitleStyles.subtitle}/> : (subtitle || null)}
184
+ </View>
185
+
164
186
  return (
165
187
  <Touchable
166
188
  style={getStyles('wrapper')}
@@ -168,6 +190,7 @@ export const TextInput = forwardRef<NativeTextInput, TextInputProps>((rawprops,
168
190
  onPress={handlePress}
169
191
  {...wrapperProps}
170
192
  android_ripple={null}
193
+ noFeedback
171
194
  >
172
195
  <InputLabel
173
196
  label={label}
@@ -214,17 +237,27 @@ export const TextInput = forwardRef<NativeTextInput, TextInputProps>((rawprops,
214
237
  />
215
238
 
216
239
  </View>
217
- <FormError message={error.message} style={getStyles('error')} />
240
+ {subtitleContent}
218
241
  </Touchable>
219
242
  )
220
243
  })
221
244
 
222
- export const FormError = ({ message, ...props }) => {
223
- if (['number', 'string', 'undefined'].includes(typeof message)) {
245
+ export const FormError:React.FC<TextProps> = ({ text, ...props }) => {
246
+ let message = text
247
+ if (TypeGuards.isNumber(message)) {
248
+ message = message.toString()
249
+ }
250
+ if (typeof message === 'undefined') {
251
+ message = ''
252
+ }
253
+
254
+ if (TypeGuards.isString(message)) {
224
255
  const text = message ? `${message.charAt(0).toUpperCase() + message.slice(1)}` : ' '
225
- return <Text text={text} variants={['p2', 'marginTop:1']} {...props} />
256
+ return <Text text={text} {...props} />
226
257
  }
227
- return message
258
+ return <>
259
+ {text}
260
+ </>
228
261
  }
229
262
 
230
263
  type InputIconProps = {
@@ -237,7 +270,8 @@ type InputIconProps = {
237
270
  export const InputIcon:React.FC<InputIconProps> = ({ styles, commonStyles, isFocused, showError, ...props }) => {
238
271
  if (!props.icon) return null
239
272
 
240
- function getStyles(key: ActionIconParts | '') {
273
+ function getStyles(k: ActionIconParts | '') {
274
+ let key = k
241
275
  if (key === 'icon') key = ''
242
276
  const requestedStyles = [
243
277
  commonStyles[key],
@@ -247,13 +281,14 @@ export const InputIcon:React.FC<InputIconProps> = ({ styles, commonStyles, isFoc
247
281
  isFocused ? styles[key + ':focus'] : {},
248
282
  showError ? styles[key + ':error'] : {},
249
283
  ]
284
+
250
285
  return StyleSheet.flatten(requestedStyles)
251
286
  }
252
287
  const iconStyles = {
253
288
  icon: getStyles('icon'),
254
289
  touchablePressable: getStyles('touchablePressable'),
255
290
  touchableWrapper: getStyles('touchableWrapper'),
256
- touchableRipple: getStyles('touchableRipple'),
291
+ touchableFeedback: getStyles('touchableFeedback'),
257
292
  }
258
293
 
259
294
  return <ActionIcon
@@ -14,6 +14,8 @@ type TextInputParts =
14
14
  | 'label'
15
15
  | 'innerWrapper'
16
16
  | 'error'
17
+ | 'subtitle'
18
+ | 'subtitleWrapper'
17
19
  | 'placeholder'
18
20
  | 'selection'
19
21
  | 'requiredAsterisk'
@@ -74,16 +76,24 @@ export const TextInputStyles = {
74
76
  color: theme.colors.primary,
75
77
  },
76
78
  leftIconTouchableWrapper: {
77
- ...theme.spacing.marginRight(1),
79
+ // ...theme.spacing.marginRight(0.5),
78
80
  },
79
81
  rightIconTouchableWrapper: {
80
- ...theme.spacing.marginLeft(1),
82
+ // ...theme.spacing.marginLeft(0.5),
81
83
  },
82
84
  error: {
83
85
  color: theme.colors.negative,
84
- ...theme.spacing.marginTop(0.5),
85
- },
86
86
 
87
+ },
88
+ subtitleWrapper: {
89
+ ...theme.spacing.marginTop(0.2),
90
+ ...theme.presets.row,
91
+ ...theme.presets.justifySpaceBetween,
92
+ ...theme.presets.alignCenter,
93
+ },
94
+ subtitle: {
95
+ ...theme.presets.textRight,
96
+ },
87
97
  'label:error': {
88
98
  color: theme.colors.negative,
89
99
  },