@widergy/mobile-ui 1.10.2 → 1.10.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.10.3](https://github.com/widergy/mobile-ui/compare/v1.10.2...v1.10.3) (2024-05-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add button component ([#277](https://github.com/widergy/mobile-ui/issues/277)) ([14407ae](https://github.com/widergy/mobile-ui/commit/14407ae6d65e5cf949950c7e359fc16892756cf0))
7
+
1
8
  ## [1.10.2](https://github.com/widergy/mobile-ui/compare/v1.10.1...v1.10.2) (2024-05-22)
2
9
 
3
10
 
@@ -7,7 +7,7 @@ import { withTheme, themeType } from '../../theming';
7
7
  import IconButton from '../IconButton';
8
8
  import Label from '../Label';
9
9
  import { IS_ANDROID } from '../../utils/platformUtils/constants';
10
- import { SHADOW_COLOR, SHADOW_OPACITY } from '../Surface/constants';
10
+ import { SHADOW_COLOR, SHADOW_OPACITY } from '../../utils/styleUtils';
11
11
 
12
12
  import styles, { alertStyleMapper } from './styles';
13
13
  import { INFO, DURATION } from './constants';
@@ -1,31 +1 @@
1
1
  export const DEFAULT_ELEVATION = 2;
2
-
3
- export const SHADOW_COLOR = 'black';
4
- export const SHADOW_OPACITY = 0.24;
5
-
6
- export const calculateShadow = elevation => {
7
- let height;
8
- let radius;
9
- switch (elevation) {
10
- case 1:
11
- height = 0.5;
12
- radius = 0.75;
13
- break;
14
- case 2:
15
- height = 0.75;
16
- radius = 1.5;
17
- break;
18
- default:
19
- height = elevation - 1;
20
- radius = elevation;
21
- }
22
- return {
23
- shadowColor: SHADOW_COLOR,
24
- shadowOffset: {
25
- width: 0,
26
- height
27
- },
28
- shadowOpacity: SHADOW_OPACITY,
29
- shadowRadius: radius
30
- };
31
- };
@@ -1,14 +1,14 @@
1
1
  import React from 'react';
2
2
  import { Animated, StyleSheet } from 'react-native';
3
3
 
4
- import { IS_ANDROID } from '../../utils/platformUtils/constants';
4
+ import { getShadow } from '../../utils/styleUtils';
5
5
 
6
+ import { DEFAULT_ELEVATION } from './constants';
6
7
  import propTypes from './propTypes';
7
8
  import styles from './styles';
8
- import { DEFAULT_ELEVATION, calculateShadow } from './constants';
9
9
 
10
10
  const Surface = ({ children, elevation, style, ...props }) => {
11
- const shadow = !IS_ANDROID ? calculateShadow(elevation) : { elevation };
11
+ const shadow = getShadow(elevation);
12
12
  const flatStyles = style ? StyleSheet.flatten(style) : {};
13
13
  return (
14
14
  <Animated.View style={[styles.container, flatStyles, shadow]} {...props}>
@@ -0,0 +1,34 @@
1
+ # UTButton
2
+
3
+ ### Description
4
+ Basic button component.
5
+
6
+ ### Variants
7
+ These variants were defined by the UX team and are:
8
+
9
+ - `filled`
10
+ - `outlined`
11
+ - `text`
12
+ - `semitransparent`
13
+
14
+ All these variants are defined in the component theme.
15
+
16
+ ### Color Themes
17
+ The color themes are defined by the component consumer and will vary accordingly.They define a set of variables (colors and opacities) that then combined with the variant will change how the buttons looks.
18
+ The components supports an infinite amount of color themes but requieres the consumer to pass at least a `primary` one that works as a default.
19
+
20
+ ### Props
21
+
22
+ | Name | Type | Default | Description |
23
+ |----------------------|-------------------------------------------------------|-----------|--------------------------------------------------------------------------------|
24
+ | children | node | | The component contents. |
25
+ | classNames | object | | Overrides the default button theme. |
26
+ | colorTheme | string | 'primary' | The color theme to use. |
27
+ | disabled | bool | false | If `true` the button is unclickable. |
28
+ | Icon | node | | An Icon component that can be displayed within the button. |
29
+ | iconPlacement | 'left' \| 'right' | 'left' | Indicates where the icon is placed in relation with the contents of the button |
30
+ | loading | bool | false | If `true` a spinner is shown over the component. |
31
+ | onClick | func | | Callback fired when the user clicks the component. |
32
+ | showTextOnResponsive | bool | false | If `true` and Icon is not `null` the contents of the button are not displayed. |
33
+ | size | 'small' \| 'medium' \| 'large' | 'medium' | The size of the component. |
34
+ | variant | 'filled' \| 'outlined' \| 'text' \| 'semitransparent' | 'filled' | The variant to use. |
@@ -0,0 +1,30 @@
1
+ export const ELEVATION = 3;
2
+ export const PRESSED_ELEVATION = 6;
3
+
4
+ export const SIZES = {
5
+ small: 'small',
6
+ medium: 'medium',
7
+ large: 'large'
8
+ };
9
+
10
+ export const ICON_PLACEMENTS = {
11
+ left: 'left',
12
+ right: 'right'
13
+ };
14
+
15
+ export const DEFAULT_PROPS = {
16
+ colorTheme: 'secondary',
17
+ disabled: false,
18
+ iconPlacement: ICON_PLACEMENTS.left,
19
+ loading: false,
20
+ size: SIZES.medium,
21
+ variant: 'filled'
22
+ };
23
+
24
+ export const COLORS_MAPPER = {
25
+ error: 'error',
26
+ negative: 'negative',
27
+ primary: 'accent',
28
+ secondary: 'neutral',
29
+ success: 'success'
30
+ };
@@ -0,0 +1,91 @@
1
+ import React from 'react';
2
+ import { bool, func, elementType, objectOf, string } from 'prop-types';
3
+ import { Pressable, Text, View } from 'react-native';
4
+
5
+ import { withTheme } from '../../theming';
6
+ import UTIcon from '../UTIcon';
7
+ import UTLoading from '../UTLoading';
8
+
9
+ import { DEFAULT_PROPS, ICON_PLACEMENTS } from './constants';
10
+ import { retrieveStyle } from './theme';
11
+ import { isReactComponent } from './utils';
12
+
13
+ const UTButton = ({
14
+ children,
15
+ classNames,
16
+ colorTheme,
17
+ disabled,
18
+ Icon,
19
+ iconPlacement,
20
+ loading,
21
+ onPress,
22
+ size,
23
+ theme,
24
+ variant
25
+ }) => {
26
+ const {
27
+ buttonStyles: themeButtonStyles,
28
+ childrenContainerStyles: themeChildrenContainerStyles,
29
+ disabled: disabledStyles,
30
+ iconStyles: themeIconStyles,
31
+ textStyles: themeTextStyles
32
+ } = retrieveStyle({
33
+ classNames,
34
+ colorTheme,
35
+ iconPlacement,
36
+ size,
37
+ theme,
38
+ variant
39
+ });
40
+
41
+ const iconClassname = children ? themeIconStyles.icon : themeIconStyles.iconOnly;
42
+
43
+ const buttonClassname = ({ pressed }) => [
44
+ themeButtonStyles,
45
+ (disabled || loading) && disabledStyles,
46
+ pressed ? themeButtonStyles.pressed : themeButtonStyles.notPressed
47
+ ];
48
+
49
+ const textClassname = themeTextStyles;
50
+
51
+ const IconToShow =
52
+ Icon &&
53
+ (isReactComponent(Icon) ? (
54
+ <Icon style={iconClassname} fill={themeTextStyles.color} />
55
+ ) : (
56
+ <UTIcon color={themeTextStyles.color} style={iconClassname} size={iconClassname.fontSize} {...Icon} />
57
+ ));
58
+
59
+ const RenderedChildren = (
60
+ <View style={themeChildrenContainerStyles}>
61
+ {iconPlacement === ICON_PLACEMENTS.left && IconToShow}
62
+ {children && <Text style={textClassname}>{children}</Text>}
63
+ {iconPlacement !== ICON_PLACEMENTS.left && IconToShow}
64
+ </View>
65
+ );
66
+
67
+ return (
68
+ <Pressable disabled={disabled || loading} onPress={onPress} style={buttonClassname}>
69
+ <UTLoading color={themeTextStyles.color} loading={loading} size={24} thickness={2}>
70
+ {RenderedChildren}
71
+ </UTLoading>
72
+ </Pressable>
73
+ );
74
+ };
75
+
76
+ UTButton.defaultProps = DEFAULT_PROPS;
77
+
78
+ UTButton.propTypes = {
79
+ classNames: objectOf(string),
80
+ colorTheme: string,
81
+ disabled: bool,
82
+ Icon: elementType,
83
+ iconPlacement: string,
84
+ loading: bool,
85
+ onPress: func,
86
+ size: string,
87
+ theme: objectOf(string),
88
+ variant: string
89
+ };
90
+
91
+ export default withTheme(UTButton);
@@ -0,0 +1,227 @@
1
+ import { getShadow } from '../../utils/styleUtils';
2
+
3
+ import { COLORS_MAPPER, DEFAULT_PROPS, ELEVATION, PRESSED_ELEVATION } from './constants';
4
+
5
+ const baseButtonTheme = theme => ({
6
+ text: {
7
+ fontFamily: theme.fonts.fontFamily,
8
+ fontSize: 16,
9
+ fontWeight: '500',
10
+ lineHeight: 22,
11
+ textTransform: 'none'
12
+ },
13
+ button: {
14
+ borderRadius: 4,
15
+ borderWidth: 0,
16
+ minWidth: 'auto',
17
+ paddingHorizontal: 12,
18
+ paddingVertical: 8
19
+ },
20
+ icon: {
21
+ fontSize: 20
22
+ },
23
+ iconOnly: {
24
+ fontSize: 24,
25
+ height: 24,
26
+ marginHorizontal: -4,
27
+ marginLeft: 0,
28
+ marginRight: 0,
29
+ width: 24
30
+ },
31
+ childrenContainer: {
32
+ alignItems: 'center',
33
+ display: 'flex',
34
+ flexDirection: 'row',
35
+ justifyContent: 'flex-start'
36
+ }
37
+ });
38
+
39
+ const variantsColorTheme = (theme, colorTheme, variant) => {
40
+ const actionColorName = COLORS_MAPPER[colorTheme] || COLORS_MAPPER[DEFAULT_PROPS.colorTheme];
41
+ const actionTheme = theme.Palette.actions[actionColorName];
42
+ const negativeTheme = theme.Palette.actions[COLORS_MAPPER.negative];
43
+ const neutralTheme = theme.Palette.actions[COLORS_MAPPER.secondary];
44
+ const shadow = getShadow(ELEVATION);
45
+ const pressedShadow = getShadow(PRESSED_ELEVATION);
46
+
47
+ const definition = {
48
+ filled: {
49
+ button: {
50
+ backgroundColor: actionTheme['04'],
51
+ borderColor: 'transparent',
52
+ borderWidth: 1,
53
+ fill: colorTheme === COLORS_MAPPER.negative ? neutralTheme['05'] : negativeTheme['05'],
54
+ pressed: {
55
+ backgroundColor: actionTheme['05']
56
+ }
57
+ },
58
+ text: {
59
+ color: colorTheme === COLORS_MAPPER.negative ? neutralTheme['05'] : negativeTheme['05']
60
+ },
61
+ disabled: {
62
+ backgroundColor: actionTheme['04'],
63
+ color: colorTheme === COLORS_MAPPER.negative ? neutralTheme['05'] : negativeTheme['05'],
64
+ opacity: 0.5
65
+ }
66
+ },
67
+ semitransparent: {
68
+ button: {
69
+ backgroundColor: actionTheme['01'],
70
+ borderWidth: 1,
71
+ borderColor: 'transparent',
72
+ fill: actionTheme['05'],
73
+ pressed: {
74
+ backgroundColor: actionTheme['03']
75
+ }
76
+ },
77
+ text: {
78
+ color: actionTheme['05']
79
+ },
80
+ disabled: {
81
+ backgroundColor: actionTheme['01'],
82
+ color: actionTheme['05'],
83
+ opacity: 0.5
84
+ }
85
+ },
86
+ outlined: {
87
+ button: {
88
+ borderWidth: 1,
89
+ borderColor: actionTheme['05'],
90
+ fill: actionTheme['05'],
91
+ pressed: {
92
+ backgroundColor: actionTheme['02']
93
+ }
94
+ },
95
+ text: {
96
+ color: actionTheme['05']
97
+ },
98
+ disabled: {
99
+ borderWidth: 1,
100
+ borderColor: actionTheme['05'],
101
+ color: actionTheme['05'],
102
+ opacity: 0.5
103
+ }
104
+ },
105
+ text: {
106
+ button: {
107
+ borderWidth: 1,
108
+ borderColor: 'transparent',
109
+ fill: actionTheme['05'],
110
+ pressed: {
111
+ backgroundColor: actionTheme['02']
112
+ }
113
+ },
114
+ text: {
115
+ color: actionTheme['05']
116
+ },
117
+ disabled: {
118
+ color: actionTheme['05'],
119
+ opacity: 0.5
120
+ }
121
+ },
122
+ shadow: {
123
+ button: {
124
+ backgroundColor: colorTheme === COLORS_MAPPER.negative ? neutralTheme['05'] : negativeTheme['05'],
125
+ borderWidth: 1,
126
+ borderColor: 'transparent',
127
+ fill: actionTheme['05'],
128
+ pressed: {
129
+ ...(colorTheme === COLORS_MAPPER.negative ? {} : pressedShadow),
130
+ backgroundColor: actionTheme['02']
131
+ },
132
+ notPressed: shadow
133
+ },
134
+ text: {
135
+ color: actionTheme['05']
136
+ },
137
+ disabled: {
138
+ color: actionTheme['05'],
139
+ opacity: 0.5
140
+ }
141
+ }
142
+ };
143
+
144
+ return definition[variant] || definition[DEFAULT_PROPS.variant];
145
+ };
146
+
147
+ const sizeButtonTheme = size => {
148
+ const definition = {
149
+ large: {
150
+ button: {
151
+ paddingHorizontal: 16,
152
+ paddingVertical: 12
153
+ },
154
+ text: {
155
+ fontSize: 16,
156
+ fontWeight: '500'
157
+ },
158
+ icon: {
159
+ fontSize: 20
160
+ },
161
+ iconOnly: {
162
+ fontSize: 24
163
+ }
164
+ },
165
+ small: {
166
+ button: {
167
+ paddingHorizontal: 8,
168
+ paddingVertical: 4
169
+ },
170
+ text: {
171
+ fontSize: 14,
172
+ fontWeight: '500'
173
+ },
174
+ icon: {
175
+ fontSize: 20
176
+ },
177
+ iconOnly: {
178
+ fontSize: 24
179
+ }
180
+ }
181
+ };
182
+
183
+ return definition[size] || {};
184
+ };
185
+
186
+ const iconButtonPlacementTheme = iconPlacement => {
187
+ const definition = {
188
+ left: {
189
+ marginRight: 8
190
+ },
191
+ right: {
192
+ marginLeft: 8
193
+ }
194
+ };
195
+ return definition[iconPlacement] || {};
196
+ };
197
+
198
+ export const retrieveStyle = ({ classNames = {}, colorTheme, variant, theme, size, iconPlacement }) => {
199
+ const baseTheme = baseButtonTheme(theme);
200
+ const variantTheme = variantsColorTheme(theme, colorTheme, variant);
201
+ const sizeTheme = sizeButtonTheme(size);
202
+ const iconPlacementTheme = iconButtonPlacementTheme(iconPlacement);
203
+
204
+ const buttonStyles = {
205
+ ...baseTheme.button,
206
+ ...variantTheme.button,
207
+ ...sizeTheme.button,
208
+ ...classNames.root
209
+ };
210
+
211
+ const textStyles = {
212
+ ...baseTheme.text,
213
+ ...variantTheme.text,
214
+ ...sizeTheme.text
215
+ };
216
+
217
+ const iconStyles = {
218
+ icon: { ...baseTheme.icon, ...sizeTheme.icon, ...iconPlacementTheme, ...classNames.icon },
219
+ iconOnly: { ...baseTheme.iconOnly, ...sizeTheme.iconOnly, ...classNames.icon }
220
+ };
221
+
222
+ const childrenContainerStyles = { ...baseTheme.childrenContainer, ...classNames.childrenContainer };
223
+
224
+ const { disabled } = variantTheme;
225
+
226
+ return { buttonStyles, textStyles, disabledStyles: disabled, iconStyles, childrenContainerStyles };
227
+ };
@@ -0,0 +1 @@
1
+ export const isReactComponent = icon => typeof icon === 'function';
package/lib/index.js CHANGED
@@ -1,5 +1,10 @@
1
+ import ReactotronConfig from './reactotronConfig'; // Importa la configuración de Reactotron
2
+
3
+ ReactotronConfig();
4
+
1
5
  // Buttons
2
6
  export { default as Button } from './components/Button';
7
+ export { default as UTButton } from './components/UTButton';
3
8
  export { default as IconButton } from './components/IconButton';
4
9
  export { default as ImageButton } from './components/ImageButton';
5
10
  export { default as Touchable } from './components/Touchable';
@@ -0,0 +1,7 @@
1
+ import Reactotron from 'reactotron-react-native';
2
+
3
+ const configureReactotron = () => {
4
+ Reactotron.configure().useReactNative().connect();
5
+ };
6
+
7
+ export default configureReactotron;
@@ -2,6 +2,76 @@ import { shape, string, number, object } from 'prop-types';
2
2
 
3
3
  import { moderateHorizontalScale, verticalScale } from '../utils/scaleUtils';
4
4
 
5
+ const colors = {
6
+ actionAccent01: '#FCF1E5',
7
+ actionAccent02: '#F8DCBF',
8
+ actionAccent03: '#EB9540',
9
+ actionAccent04: '#E57200',
10
+ actionAccent05: '#8F3300',
11
+
12
+ actionNeutral01: '#E5ECF0',
13
+ actionNeutral02: '#BFD0DB',
14
+ actionNeutral03: '#407495',
15
+ actionNeutral04: '#004571',
16
+ actionNeutral05: '#00385C',
17
+
18
+ actionError01: '#FFEBEE',
19
+ actionError02: '#FECED5',
20
+ actionError03: '#FD6F85',
21
+ actionError04: '#E80C2C',
22
+ actionError05: '#A0041B',
23
+
24
+ actionNegative01: 'rgba(255, 255, 255, 0.1)',
25
+ actionNegative02: 'rgba(255, 255, 255, 0.25)',
26
+ actionNegative03: 'rgba(255, 255, 255, 0.5)',
27
+ actionNegative04: '#FFFFFF',
28
+ actionNegative05: '#FFFFFF',
29
+
30
+ semanticSuccess01: '#EEF9E6',
31
+ semanticSuccess02: '#D3F0C0',
32
+ semanticSuccess03: '#80D249',
33
+ semanticSuccess04: '#3F8411',
34
+ semanticSuccess05: '#245702'
35
+ };
36
+
37
+ const actions = {
38
+ accent: {
39
+ '01': colors.actionAccent01,
40
+ '02': colors.actionAccent02,
41
+ '03': colors.actionAccent03,
42
+ '04': colors.actionAccent04,
43
+ '05': colors.actionAccent05
44
+ },
45
+ neutral: {
46
+ '01': colors.actionNeutral01,
47
+ '02': colors.actionNeutral02,
48
+ '03': colors.actionNeutral03,
49
+ '04': colors.actionNeutral04,
50
+ '05': colors.actionNeutral05
51
+ },
52
+ error: {
53
+ '01': colors.actionError01,
54
+ '02': colors.actionError02,
55
+ '03': colors.actionError03,
56
+ '04': colors.actionError04,
57
+ '05': colors.actionError05
58
+ },
59
+ success: {
60
+ '01': colors.semanticSuccess01,
61
+ '02': colors.semanticSuccess02,
62
+ '03': colors.semanticSuccess03,
63
+ '04': colors.semanticSuccess04,
64
+ '05': colors.semanticSuccess05
65
+ },
66
+ negative: {
67
+ '01': colors.actionNegative01,
68
+ '02': colors.actionNegative02,
69
+ '03': colors.actionNegative03,
70
+ '04': colors.actionNegative04,
71
+ '05': colors.actionNegative05
72
+ }
73
+ };
74
+
5
75
  const DefaultTheme = {
6
76
  alert: {
7
77
  info: '#0065A3',
@@ -164,43 +234,7 @@ const DefaultTheme = {
164
234
  '04': '#037C96',
165
235
  '05': '#025F73'
166
236
  },
167
- actions: {
168
- accent: {
169
- '01': '#E7F0EE',
170
- '02': '#C3D9D5',
171
- '03': '#4A8D83',
172
- '04': '#0D6759',
173
- '05': '#0D6759'
174
- },
175
- neutral: {
176
- '01': '#E8ECED',
177
- '02': '#C6D0D3',
178
- '03': '#54737B',
179
- '04': '#1B444F',
180
- '05': '#1B444F'
181
- },
182
- error: {
183
- '01': '#FFEBEE',
184
- '02': '#FECED5',
185
- '03': '#FD6F85',
186
- '04': '#E80C2C',
187
- '05': '#A0041B'
188
- },
189
- success: {
190
- '01': '#EEF9E6',
191
- '02': '#D3F0C0',
192
- '03': '#80D249',
193
- '04': '#3F8411',
194
- '05': '#245702'
195
- },
196
- negative: {
197
- '01': 'rgba(255, 255, 255, 0.1)',
198
- '02': 'rgba(255, 255, 255, 0.25)',
199
- '03': 'rgba(255, 255, 255, 0.5)',
200
- '04': '#FFFFFF',
201
- '05': '#FFFFFF'
202
- }
203
- }
237
+ actions
204
238
  }
205
239
  };
206
240
 
@@ -1,3 +1,37 @@
1
+ import { IS_ANDROID } from '../platformUtils/constants';
2
+
3
+ export const SHADOW_COLOR = 'black';
4
+ export const SHADOW_OPACITY = 0.24;
5
+
6
+ export const calculateShadow = elevation => {
7
+ let height;
8
+ let radius;
9
+ switch (elevation) {
10
+ case 1:
11
+ height = 0.5;
12
+ radius = 0.75;
13
+ break;
14
+ case 2:
15
+ height = 0.75;
16
+ radius = 1.5;
17
+ break;
18
+ default:
19
+ height = elevation - 1;
20
+ radius = elevation;
21
+ }
22
+ return {
23
+ shadowColor: SHADOW_COLOR,
24
+ shadowOffset: {
25
+ width: 0,
26
+ height
27
+ },
28
+ shadowOpacity: SHADOW_OPACITY,
29
+ shadowRadius: radius
30
+ };
31
+ };
32
+
33
+ export const getShadow = elevation => (IS_ANDROID ? { elevation } : calculateShadow(elevation));
34
+
1
35
  // this is used to quickly build layout related objects in any measure callback or onLayout event
2
36
  export const generateLayoutMeasuresObject = (x, y, width, height) => ({
3
37
  left: x,
@@ -13,7 +47,21 @@ export const getCustomStyles = (variants, props, styles, stylePrefix = '') =>
13
47
  .map(variant => (props[variant] ? styles[`${variant}${stylePrefix}`] : null))
14
48
  .filter(style => style !== null);
15
49
 
50
+ export const mergeClasses = (themeClasses, classNames) => {
51
+ if (!classNames) return themeClasses;
52
+ const classes = {};
53
+ const allClassNames = [...Object.keys(classNames), ...Object.keys(themeClasses)];
54
+
55
+ allClassNames.forEach(name => {
56
+ classes[name] = `${themeClasses[name] || ''} ${classNames[name] || ''}`.trim();
57
+ });
58
+
59
+ return classes;
60
+ };
61
+
16
62
  export default {
63
+ calculateShadow,
64
+ generateLayoutMeasuresObject,
17
65
  getCustomStyles,
18
- generateLayoutMeasuresObject
66
+ mergeClasses
19
67
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@widergy/mobile-ui",
3
3
  "description": "Widergy Mobile Components",
4
4
  "author": "widergy",
5
- "version": "1.10.2",
5
+ "version": "1.10.3",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [
@@ -79,6 +79,7 @@
79
79
  "react-native": "0.72.6",
80
80
  "react-native-vector-icons": "^10.0.0",
81
81
  "react-native-version": "^4.0.0",
82
+ "reactotron-react-native": "^5.1.7",
82
83
  "semantic-release": "^15.13.31"
83
84
  },
84
85
  "release": {