@widergy/mobile-ui 1.12.7 → 1.13.1

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.1](https://github.com/widergy/mobile-ui/compare/v1.13.0...v1.13.1) (2024-07-12)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * utbutton for workflow summary and bottom actions ([#313](https://github.com/widergy/mobile-ui/issues/313)) ([54cf399](https://github.com/widergy/mobile-ui/commit/54cf399163784402c6545f15921ac7d30cbda89d))
7
+
8
+ # [1.13.0](https://github.com/widergy/mobile-ui/compare/v1.12.7...v1.13.0) (2024-07-11)
9
+
10
+
11
+ ### Features
12
+
13
+ * new loader ([#312](https://github.com/widergy/mobile-ui/issues/312)) ([2293385](https://github.com/widergy/mobile-ui/commit/229338516523e69a1d0f8104087acab2d3e9b1cb))
14
+
1
15
  ## [1.12.7](https://github.com/widergy/mobile-ui/compare/v1.12.6...v1.12.7) (2024-07-08)
2
16
 
3
17
 
@@ -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
+ useUtilityLoading: bool
53
16
  };
54
17
 
55
18
  export default UTLoading;
@@ -3,27 +3,26 @@ import { string, func, bool } from 'prop-types';
3
3
  import { View } from 'react-native';
4
4
  import merge from 'lodash/merge';
5
5
 
6
- import Button from '../../../../../../../Button';
6
+ import UTButton from '../../../../../../../UTButton';
7
7
  import { useTheme } from '../../../../../../../../theming';
8
8
 
9
9
  import ownStyles from './styles';
10
10
 
11
- const ActionButton = ({ hidden, disabled, onPress, label, mode, style }) => {
11
+ const ActionButton = ({ hidden, disabled, onPress, label, variant, style }) => {
12
12
  const theme = useTheme();
13
13
  const themedStyles = merge({}, ownStyles, theme?.UTWorkflowContainer?.actionButton, style);
14
14
 
15
15
  return (
16
16
  <View style={themedStyles.actionButton}>
17
- <Button
18
- containerStyle={themedStyles.buttonContainer}
19
- contentStyle={themedStyles.buttonContent}
17
+ <UTButton
20
18
  disabled={disabled || hidden}
21
- elevation={themedStyles.elevation}
22
- lowerCase
23
- mode={mode}
24
19
  onPress={onPress}
25
- title={label}
26
- />
20
+ size="large"
21
+ style={{ root: themedStyles.buttonContainer, childrenContainer: themedStyles.buttonContent }}
22
+ variant={variant}
23
+ >
24
+ {label}
25
+ </UTButton>
27
26
  </View>
28
27
  );
29
28
  };
@@ -32,7 +31,7 @@ ActionButton.propTypes = {
32
31
  disabled: bool,
33
32
  hidden: bool,
34
33
  label: string,
35
- mode: string,
34
+ variant: string,
36
35
  onPress: func
37
36
  };
38
37
 
@@ -5,6 +5,6 @@ export default StyleSheet.create({
5
5
  flexGrow: 1
6
6
  },
7
7
  buttonContainer: {
8
- width: '100%'
8
+ alignItems: 'center'
9
9
  }
10
10
  });
@@ -4,14 +4,14 @@ import merge from 'lodash/merge';
4
4
 
5
5
  import Label from '../../../../../Label';
6
6
  import Surface from '../../../../../Surface';
7
- import Button from '../../../../../Button';
8
7
  import Icon from '../../../../../Icon';
9
8
  import Checkbox from '../../../../../Checkbox';
10
9
  import { MessagePropTypes, SummaryPropTypes } from '../../types';
10
+ import UTButton from '../../../../../UTButton';
11
11
 
12
12
  import ActionButton from './components/ActionButton';
13
13
  import ActionButtonPropTypes from './components/ActionButton/types';
14
- import ownStyles, { ICON_SIZE } from './styles';
14
+ import ownStyles from './styles';
15
15
  import { NEXT, RETURN } from './constants';
16
16
 
17
17
  const BottomActions = ({ nextButton, returnButton, summary, message, style }) => {
@@ -39,29 +39,23 @@ const BottomActions = ({ nextButton, returnButton, summary, message, style }) =>
39
39
  )}
40
40
  {summary.actions && !checkboxProps && (
41
41
  <View style={themedStyles.summaryActions}>
42
- {summary.actions.map((action, index) => (
43
- <Button
44
- containerStyle={themedStyles.summaryActionContainer}
45
- contentStyle={!action.title && themedStyles.summaryActionButton}
46
- elevation={action.elevation}
47
- icon={
48
- action.icon && {
49
- height: action.icon.height || ICON_SIZE,
50
- name: action.icon.name,
51
- size: action.icon.size || ICON_SIZE,
52
- type: action.icon.type,
53
- width: action.icon.width || ICON_SIZE
54
- }
55
- }
56
- key={action.name}
57
- labelColor={themedStyles.summaryActions?.labelColor || 'blue'}
58
- onPress={action.onPress}
59
- outerContainerStyles={
60
- index !== summary.actions.length - 1 && themedStyles.summaryActionsChild
61
- }
62
- secondary
63
- title={action.title}
64
- />
42
+ {summary.actions.map(({ Icon: actionIcon, title, onPress }, index) => (
43
+ <UTButton
44
+ Icon={actionIcon}
45
+ key={actionIcon}
46
+ onPress={onPress}
47
+ size="small"
48
+ style={{
49
+ root: {
50
+ ...themedStyles.summaryActionContainer,
51
+ ...(index !== summary.actions.length - 1 && themedStyles.summaryActionsChild)
52
+ },
53
+ childrenContainer: themedStyles.summaryActionButton
54
+ }}
55
+ variant="semitransparent"
56
+ >
57
+ {title}
58
+ </UTButton>
65
59
  ))}
66
60
  </View>
67
61
  )}
@@ -93,7 +87,7 @@ const BottomActions = ({ nextButton, returnButton, summary, message, style }) =>
93
87
  {returnButtonEnabled && (
94
88
  <ActionButton
95
89
  label={returnButton.label || RETURN}
96
- mode="text"
90
+ variant="text"
97
91
  style={{
98
92
  actionButton: {
99
93
  ...themedStyles.returnActionButton,
@@ -1,7 +1,5 @@
1
1
  import { StyleSheet } from 'react-native';
2
2
 
3
- export const ICON_SIZE = 24;
4
-
5
3
  export default StyleSheet.create({
6
4
  actionsChild: {
7
5
  marginRight: 16
@@ -47,11 +45,8 @@ export default StyleSheet.create({
47
45
  justifyContent: 'space-between',
48
46
  padding: 16
49
47
  },
50
- summaryActionButton: {
51
- marginHorizontal: 8
52
- },
53
48
  summaryActionContainer: {
54
- minWidth: 0
49
+ paddingVertical: 8
55
50
  },
56
51
  summaryActions: {
57
52
  alignItems: 'center',
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.7",
5
+ "version": "1.13.1",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [