@widergy/mobile-ui 1.12.6 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [1.13.0](https://github.com/widergy/mobile-ui/compare/v1.12.7...v1.13.0) (2024-07-11)
2
+
3
+
4
+ ### Features
5
+
6
+ * new loader ([#312](https://github.com/widergy/mobile-ui/issues/312)) ([2293385](https://github.com/widergy/mobile-ui/commit/229338516523e69a1d0f8104087acab2d3e9b1cb))
7
+
8
+ ## [1.12.7](https://github.com/widergy/mobile-ui/compare/v1.12.6...v1.12.7) (2024-07-08)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * utmenu passes selected item value to onclose func ([#307](https://github.com/widergy/mobile-ui/issues/307)) ([b82c033](https://github.com/widergy/mobile-ui/commit/b82c033a284dfa3d647930cd33b0c5b0dfd269ce))
14
+
1
15
  ## [1.12.6](https://github.com/widergy/mobile-ui/compare/v1.12.5...v1.12.6) (2024-07-03)
2
16
 
3
17
 
@@ -1,6 +1,7 @@
1
1
  import { arrayOf, bool, element, func, oneOf, shape, string } from 'prop-types';
2
2
  import React, { useEffect, useState } from 'react';
3
3
  import { View } from 'react-native';
4
+ import { ViewPropTypes } from 'deprecated-react-native-prop-types';
4
5
 
5
6
  import { WINDOW_HEIGHT } from '../../utils/scaleUtils';
6
7
  import UTMenu from '../UTMenu';
@@ -21,7 +22,8 @@ const UTAutocomplete = ({
21
22
  MenuOptionComponent,
22
23
  options,
23
24
  persistSelectedOption = false,
24
- variant
25
+ variant,
26
+ styles: propStyles
25
27
  }) => {
26
28
  const [selectedOption, setSelectedOption] = useState();
27
29
 
@@ -54,6 +56,7 @@ const UTAutocomplete = ({
54
56
  options={options}
55
57
  selectedOption={selectedOption?.id}
56
58
  withAutocomplete
59
+ styles={propStyles?.UTMenu}
57
60
  >
58
61
  <UTTextInput
59
62
  disabled={disabled}
@@ -94,7 +97,8 @@ UTAutocomplete.propTypes = {
94
97
  })
95
98
  ),
96
99
  persistSelectedOption: bool,
97
- variant: string
100
+ variant: string,
101
+ styles: ViewPropTypes.style
98
102
  };
99
103
 
100
104
  export default UTAutocomplete;
@@ -4,24 +4,27 @@ Wraps a component within a screen and displays a loading indicator until it's do
4
4
 
5
5
  ## Props
6
6
 
7
- |NAME|TYPE|REQUIRED|DESCRIPTION|
8
- |---|---|---|---|
9
- |children|PropTypes.element|Yes|The component that you want to wrap until it's done loading|
10
- |loading|PropTypes.bool|Yes|The boolean `loading` that you want the spinner to depend on|
11
- |color|PropTypes.string|No|Color of spinner. Uses the theme's primary color by default|
12
- |size|PropTypes.number|No|The size of the spinner, defaults to `70`|
13
- |thickness|PropTypes.number|No|The thickness of the spinner, defaults to `3`|
14
- |style|ViewPropTypes.style|No|custom style applied to the spinner's container|
15
- |message|PropTypes.string|No|A message to display below the spinner|
16
- |messageStyle|ViewPropTypes.style|No|Custom style applied to the message|
7
+ | NAME | TYPE | REQUIRED | USED BY | DESCRIPTION |
8
+ | ----------------- | ------------------- | -------- | :-----------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | children | PropTypes.element | Yes | AnimatedCircles - Spinner | The component that you want to wrap until it's done loading |
10
+ | loading | PropTypes.bool | Yes | AnimatedCircles - Spinner | The boolean`loading` that you want the spinner to depend on |
11
+ | color | PropTypes.string | No | AnimatedCircles - Spinner | Color of spinner. Uses the theme's primary color by default |
12
+ | size | PropTypes.number | No | Spinner | The size of the spinner, defaults to`70` |
13
+ | thickness | PropTypes.number | No | Spinner | The thickness of the spinner, defaults to`3` |
14
+ | style | ViewPropTypes.style | No | Spinner | custom style applied to the spinner's container |
15
+ | message | PropTypes.string | No | Spinner | A message to display below the spinner |
16
+ | messageStyle | ViewPropTypes.style | No | Spinner | Custom style applied to the message |
17
+ | Logo | PropTypes.number | No | AnimatedCircles | Utility logo (png) shown above the animated circles. |
18
+ | useUtilityLoading | PropTypes.bool | No | AnimatedCircles - Spinner | Flag that determines whether to show the classic loader (spinner) or the new one (animated circles with utility logo).<br /> (_Default: classic loader_). |
17
19
 
18
20
  ## Example
21
+
19
22
  ```js
20
23
  import { Loading } from "@widergy/mobile-ui";
21
24
 
22
25
  return (
23
26
  <Label>This component does not depend on the loader</Label>
24
- <UTLoading
27
+ <UTLoading
25
28
  loading={this.props.loading}
26
29
  color="blue"
27
30
  size={200}
@@ -33,3 +36,4 @@ import { Loading } from "@widergy/mobile-ui";
33
36
  {your wrapped component goes here}
34
37
  </UTLoading>
35
38
  )
39
+ ```
@@ -0,0 +1,9 @@
1
+ export const OPACITY_LOW = 0.33;
2
+ export const OPACITY_MEDIUM = 0.66;
3
+ export const OPACITY_HIGH = 1;
4
+
5
+ export const TRANSLATE_INITIAL_VALUE = -12;
6
+ export const TRANSLATE_FINAL_VALUE = 0;
7
+
8
+ export const TRANSLATE_DURATION = 280;
9
+ export const OPACITY_DURATION = 200;
@@ -0,0 +1,112 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import React, { useEffect, useRef } from 'react';
3
+ import { Animated, Image, View } from 'react-native';
4
+ import { string, bool, node, number } from 'prop-types';
5
+
6
+ import { useTheme } from '../../../../theming';
7
+
8
+ import {
9
+ OPACITY_DURATION,
10
+ OPACITY_HIGH,
11
+ OPACITY_LOW,
12
+ OPACITY_MEDIUM,
13
+ TRANSLATE_DURATION,
14
+ TRANSLATE_FINAL_VALUE,
15
+ TRANSLATE_INITIAL_VALUE
16
+ } from './constants';
17
+ import styles from './styles';
18
+
19
+ const AnimatedCircles = ({ children, color, loading, Logo }) => {
20
+ const theme = useTheme();
21
+ const neutralTheme = theme.Palette.neutral;
22
+ const lightTheme = theme.Palette.light;
23
+ const animations = useRef([new Animated.Value(0), new Animated.Value(0), new Animated.Value(0)]).current;
24
+ const opacities = useRef([
25
+ new Animated.Value(OPACITY_HIGH),
26
+ new Animated.Value(OPACITY_LOW),
27
+ new Animated.Value(OPACITY_MEDIUM)
28
+ ]).current;
29
+
30
+ useEffect(() => {
31
+ const onAnimate = index => {
32
+ const nextIndex = (index + 1) % animations.length;
33
+ Animated.sequence([
34
+ Animated.parallel([
35
+ Animated.timing(animations[index], {
36
+ duration: TRANSLATE_DURATION,
37
+ toValue: TRANSLATE_INITIAL_VALUE,
38
+ useNativeDriver: true
39
+ }),
40
+ Animated.timing(opacities[index], {
41
+ duration: OPACITY_DURATION,
42
+ toValue: OPACITY_HIGH,
43
+ useNativeDriver: true
44
+ })
45
+ ]),
46
+ Animated.delay(500),
47
+ Animated.parallel([
48
+ Animated.timing(animations[index], {
49
+ duration: TRANSLATE_DURATION,
50
+ toValue: TRANSLATE_FINAL_VALUE,
51
+ useNativeDriver: true
52
+ }),
53
+ Animated.timing(opacities[index], {
54
+ duration: OPACITY_DURATION,
55
+ toValue: OPACITY_MEDIUM,
56
+ useNativeDriver: true
57
+ }),
58
+ Animated.timing(animations[nextIndex], {
59
+ duration: TRANSLATE_DURATION,
60
+ toValue: TRANSLATE_INITIAL_VALUE,
61
+ useNativeDriver: true
62
+ }),
63
+ Animated.timing(opacities[nextIndex], {
64
+ duration: OPACITY_DURATION,
65
+ toValue: OPACITY_HIGH,
66
+ useNativeDriver: true
67
+ }),
68
+ Animated.timing(opacities[(index + 2) % animations.length], {
69
+ duration: OPACITY_DURATION,
70
+ toValue: OPACITY_LOW,
71
+ useNativeDriver: true
72
+ })
73
+ ])
74
+ ]).start(() => {
75
+ onAnimate(nextIndex);
76
+ });
77
+ };
78
+
79
+ onAnimate(0);
80
+ }, [animations, opacities]);
81
+
82
+ return loading ? (
83
+ <View style={{ ...styles.container, backgroundColor: lightTheme['01'] }}>
84
+ {Logo && <Image resizeMode="contain" source={Logo} style={styles.imageStyle} />}
85
+
86
+ <View style={styles.circlesContainer}>
87
+ {animations.map((_, index) => (
88
+ <Animated.View
89
+ key={index}
90
+ style={[
91
+ { ...styles.circle, backgroundColor: color || neutralTheme['04'] },
92
+ { transform: [{ translateY: animations[index] }], opacity: opacities[index] }
93
+ ]}
94
+ />
95
+ ))}
96
+ </View>
97
+ </View>
98
+ ) : (
99
+ children
100
+ );
101
+ };
102
+
103
+ AnimatedCircles.displayName = 'UTLoading';
104
+
105
+ AnimatedCircles.propTypes = {
106
+ children: node,
107
+ color: string,
108
+ loading: bool,
109
+ Logo: number
110
+ };
111
+
112
+ export default AnimatedCircles;
@@ -0,0 +1,28 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { verticalScale } from '../../../../utils/scaleUtils';
4
+
5
+ export default StyleSheet.create({
6
+ container: {
7
+ alignItems: 'center',
8
+ backgroundColor: '#ffffff',
9
+ flex: 1,
10
+ flexDirection: 'column',
11
+ justifyContent: 'center',
12
+ width: '100%'
13
+ },
14
+ circlesContainer: {
15
+ marginTop: 50,
16
+ flexDirection: 'row'
17
+ },
18
+ circle: {
19
+ backgroundColor: '#000000',
20
+ borderRadius: 10,
21
+ height: 16,
22
+ margin: 4,
23
+ width: 16
24
+ },
25
+ imageStyle: {
26
+ height: verticalScale(40)
27
+ }
28
+ });
@@ -0,0 +1,56 @@
1
+ import React, { Fragment } from 'react';
2
+ import { number, string, bool } from 'prop-types';
3
+ import { View } from 'react-native';
4
+ import { ViewPropTypes } from 'deprecated-react-native-prop-types';
5
+
6
+ import Loading from '../../../Loading';
7
+
8
+ import styles from './styles';
9
+
10
+ const Spinner = ({
11
+ children,
12
+ color,
13
+ loading,
14
+ message,
15
+ messageStyle,
16
+ preventUnmount,
17
+ size,
18
+ style,
19
+ thickness
20
+ }) => {
21
+ return (
22
+ <Fragment>
23
+ {!!loading && (
24
+ <Loading
25
+ style={[styles.spinner, style]}
26
+ message={message}
27
+ color={color}
28
+ size={size}
29
+ thickness={thickness}
30
+ messageStyle={messageStyle}
31
+ />
32
+ )}
33
+ {preventUnmount ? (
34
+ // eslint-disable-next-line react-native/no-inline-styles
35
+ <View style={{ display: loading ? 'none' : 'flex' }}>{children}</View>
36
+ ) : (
37
+ !loading && children
38
+ )}
39
+ </Fragment>
40
+ );
41
+ };
42
+
43
+ Spinner.displayName = 'UTLoading';
44
+
45
+ Spinner.propTypes = {
46
+ color: string,
47
+ loading: bool,
48
+ message: string,
49
+ messageStyle: ViewPropTypes.style,
50
+ preventUnmount: bool,
51
+ size: number,
52
+ style: ViewPropTypes.style,
53
+ thickness: number
54
+ };
55
+
56
+ export default Spinner;
@@ -1,55 +1,18 @@
1
- import React, { Fragment } from 'react';
2
- import { number, string, bool } from 'prop-types';
3
- import { View } from 'react-native';
4
- import { ViewPropTypes } from 'deprecated-react-native-prop-types';
1
+ import React from 'react';
2
+ import { bool } from 'prop-types';
5
3
 
6
- import Loading from '../Loading';
4
+ import AnimatedCircles from './components/AnimatedCircles';
5
+ import Spinner from './components/Spinner';
7
6
 
8
- import styles from './styles';
9
-
10
- const UTLoading = ({
11
- children,
12
- color,
13
- loading,
14
- message,
15
- messageStyle,
16
- preventUnmount,
17
- size,
18
- style,
19
- thickness
20
- }) => {
21
- return (
22
- <Fragment>
23
- {!!loading && (
24
- <Loading
25
- style={[styles.spinner, style]}
26
- message={message}
27
- color={color}
28
- size={size}
29
- thickness={thickness}
30
- messageStyle={messageStyle}
31
- />
32
- )}
33
- {preventUnmount ? (
34
- <View style={{ display: loading ? 'none' : 'flex' }}>{children}</View>
35
- ) : (
36
- !loading && children
37
- )}
38
- </Fragment>
39
- );
7
+ const UTLoading = props => {
8
+ const { useUtilityLoading } = props || {};
9
+ return useUtilityLoading ? <AnimatedCircles {...props} /> : <Spinner {...props} />;
40
10
  };
41
11
 
42
12
  UTLoading.displayName = 'UTLoading';
43
13
 
44
14
  UTLoading.propTypes = {
45
- color: string,
46
- loading: bool,
47
- message: string,
48
- messageStyle: ViewPropTypes.style,
49
- preventUnmount: bool,
50
- size: number,
51
- style: ViewPropTypes.style,
52
- thickness: number
15
+ useUtilityLoader: bool
53
16
  };
54
17
 
55
18
  export default UTLoading;
@@ -28,7 +28,7 @@ class ListView extends PureComponent {
28
28
 
29
29
  handleOnPress = item => {
30
30
  const { handleOptionPress, onPress } = this.props;
31
- return handleOptionPress(item.action || (() => onPress(item)));
31
+ return handleOptionPress(item.action || (() => onPress(item)), item?.value);
32
32
  };
33
33
 
34
34
  renderItem = ({ item }) => {
@@ -3,6 +3,7 @@ import { Dimensions, Keyboard, KeyboardAvoidingView, Modal, TouchableOpacity, Vi
3
3
 
4
4
  import useKeyboardHeight from '../../hooks/useKeyboardHeight';
5
5
  import UTTextInput from '../UTTextInput';
6
+ import Surface from '../Surface';
6
7
 
7
8
  import MenuOption from './components/MenuOption';
8
9
  import ListView from './components/ListView';
@@ -101,15 +102,15 @@ const UTMenu = ({
101
102
  setTimeout(() => setIsOpen(true), 20);
102
103
  if (onOpen) onOpen();
103
104
  };
104
- const closeMenu = () => {
105
+ const closeMenu = value => {
105
106
  setIsOpen(false);
106
107
  setQuery('');
107
- if (onClose) onClose();
108
+ if (onClose) onClose(value);
108
109
  };
109
110
 
110
- const handleOptionPress = action => {
111
+ const handleOptionPress = (action, value) => {
111
112
  action();
112
- if (!isMultiple) closeMenu();
113
+ if (!isMultiple) closeMenu(value);
113
114
  };
114
115
 
115
116
  const focusSearchInput = () => withAutocomplete && searchTextInputRef.current?.focus();
@@ -140,14 +141,14 @@ const UTMenu = ({
140
141
  <TouchableOpacity onPress={closeMenu} style={styles.overlayTouchable}>
141
142
  <View style={styles.overlay} />
142
143
  </TouchableOpacity>
143
- <View
144
+ <Surface
144
145
  style={[styles.menu, position, fullWidth && { width: anchorMeasure?.width }, propStyles?.menu]}
145
146
  ref={menuRef}
146
147
  onLayout={handleMenuLayout}
147
148
  >
148
149
  <KeyboardAvoidingView behavior="height">
149
150
  {withAutocomplete && (
150
- <View style={styles.searchContainer}>
151
+ <View style={[styles.searchContainer, propStyles?.searchContainer]}>
151
152
  <UTTextInput
152
153
  InputRef={searchTextInputRef}
153
154
  value={query}
@@ -177,7 +178,7 @@ const UTMenu = ({
177
178
  isMultiple={isMultiple}
178
179
  />
179
180
  </KeyboardAvoidingView>
180
- </View>
181
+ </Surface>
181
182
  </Modal>
182
183
  </Fragment>
183
184
  );
@@ -7,7 +7,6 @@ export default StyleSheet.create({
7
7
  left: 0,
8
8
  backgroundColor: 'white',
9
9
  borderRadius: 8,
10
- elevation: 5,
11
10
  paddingVertical: 4
12
11
  },
13
12
  overlay: {
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.12.6",
5
+ "version": "1.13.0",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [