@widergy/mobile-ui 2.17.1 → 2.18.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 +18 -2
- package/lib/components/UTLoading/README.md +109 -31
- package/lib/components/UTLoading/index.js +9 -9
- package/lib/components/UTLoading/{components → versions/V0/components}/AnimatedCircles/index.js +1 -1
- package/lib/components/UTLoading/{components → versions/V0/components}/AnimatedCircles/styles.js +16 -13
- package/lib/components/UTLoading/{components → versions/V0/components}/Spinner/index.js +4 -4
- package/lib/components/UTLoading/{components → versions/V0/components}/Spinner/styles.js +0 -3
- package/lib/components/UTLoading/versions/V0/index.js +18 -0
- package/lib/components/UTLoading/versions/V1/components/LoaderWithLogo/index.js +84 -0
- package/lib/components/UTLoading/versions/V1/components/LoaderWithLogo/theme.js +45 -0
- package/lib/components/UTLoading/versions/V1/components/Spinner/constants.js +5 -0
- package/lib/components/UTLoading/versions/V1/components/Spinner/index.js +143 -0
- package/lib/components/UTLoading/versions/V1/components/Spinner/theme.js +23 -0
- package/lib/components/UTLoading/versions/V1/index.js +33 -0
- package/lib/constants/testIds.js +6 -0
- package/package.json +1 -1
- /package/lib/components/UTLoading/{components → versions/V0/components}/AnimatedCircles/constants.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
# [2.18.0](https://github.com/widergy/mobile-ui/compare/v2.17.1...v2.18.0) (2026-06-07)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* fix ([81b84c4](https://github.com/widergy/mobile-ui/commit/81b84c4f673b19883b8030102a31d3ef3da3968b))
|
|
7
|
+
* fix ([d86eab3](https://github.com/widergy/mobile-ui/commit/d86eab32c35d07cdafa14a24467d61311511c8a6))
|
|
8
|
+
* fix ([1bafddb](https://github.com/widergy/mobile-ui/commit/1bafddbd5d45c300cfcba13f9b16a3edcc877332))
|
|
9
|
+
* fixes ([424a166](https://github.com/widergy/mobile-ui/commit/424a1667af7df6a84524452b6e83d264b03013d4))
|
|
10
|
+
* fixes ([edc2cda](https://github.com/widergy/mobile-ui/commit/edc2cdaa5a543e529c1549d6e0a4d03cf5efc0dc))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* [CX-2399] add V1 to UTLoading with new Spinner and LoaderWithLogo ([20c95f7](https://github.com/widergy/mobile-ui/commit/20c95f791209175e6c3bb4218af8689e1a9979ee))
|
|
16
|
+
|
|
17
|
+
## [2.17.1](https://github.com/widergy/mobile-ui/compare/v2.17.0...v2.17.1) (2026-06-05)
|
|
18
|
+
|
|
19
|
+
### Novedades y Mejoras
|
|
20
|
+
|
|
21
|
+
* Se incorporó un nuevo selector de fechas para mobile con calendario visual y posibilidad de ingresar la fecha manualmente. Permite configurar rangos de fechas permitidas, diferentes tamaños y modos de visualización, además de soportar estados como deshabilitado, solo lectura y campos obligatorios con mensajes de ayuda o error. [#507](https://github.com/widergy/Energy-UI-Mobile/pull/507) [DIS-1103](https://widergy.atlassian.net/browse/DIS-1103)
|
|
22
|
+
* Mejoras internas de la plataforma. [`7e0a800`](https://github.com/widergy/Energy-UI-Mobile/commit/7e0a800)
|
|
7
23
|
|
|
8
24
|
# [2.17.0](https://github.com/widergy/mobile-ui/compare/v2.16.0...v2.17.0) (2026-06-03)
|
|
9
25
|
|
|
@@ -1,39 +1,117 @@
|
|
|
1
1
|
# UTLoading
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Envuelve un componente y muestra un indicador de carga mientras la prop `loading` es `true`. Soporta dos versiones: V0 (comportamiento original) y V1 (nuevo diseño con spinner SVG y loader con logo).
|
|
4
4
|
|
|
5
|
-
## Props
|
|
5
|
+
## Props comunes
|
|
6
6
|
|
|
7
|
-
|
|
|
8
|
-
| ----------------- | ------------------- |
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
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_). |
|
|
7
|
+
| Nombre | Tipo | Requerido | Descripción |
|
|
8
|
+
| ----------------- | ------------------- | --------- | --------------------------------------------------------------------------- |
|
|
9
|
+
| loading | bool | Sí | Controla si se muestra el indicador de carga |
|
|
10
|
+
| version | string | No | Versión del componente: `'V0'` (default) o `'V1'` |
|
|
11
|
+
| useUtilityLoading | bool | No | En V0: muestra AnimatedCircles en lugar del Spinner. En V1: muestra LoaderWithLogo en lugar de NewSpinner |
|
|
19
12
|
|
|
20
|
-
##
|
|
13
|
+
## V0 — Comportamiento original (default)
|
|
14
|
+
|
|
15
|
+
Cuando `useUtilityLoading` es `false` (default): spinner Material Design.
|
|
16
|
+
Cuando `useUtilityLoading` es `true`: logo del cliente + tres círculos animados.
|
|
17
|
+
|
|
18
|
+
### Props adicionales de V0
|
|
19
|
+
|
|
20
|
+
| Nombre | Tipo | Usado por | Descripción |
|
|
21
|
+
| ------------- | ------------------- | --------------------------- | ------------------------------------------------ |
|
|
22
|
+
| children | node | AnimatedCircles - Spinner | Componente a mostrar cuando `loading` es `false` |
|
|
23
|
+
| color | string | AnimatedCircles - Spinner | Color del spinner |
|
|
24
|
+
| Logo | number | AnimatedCircles | Asset del logo de la utility (`require()`) |
|
|
25
|
+
| message | string | Spinner | Texto debajo del spinner |
|
|
26
|
+
| messageStyle | style | Spinner | Estilo del texto |
|
|
27
|
+
| preventUnmount| bool | Spinner | Mantiene el children montado durante la carga |
|
|
28
|
+
| size | number | Spinner | Tamaño del spinner (default: 70) |
|
|
29
|
+
| style | style | Spinner | Estilo del contenedor |
|
|
30
|
+
| thickness | number | Spinner | Grosor del spinner (default: 3) |
|
|
31
|
+
|
|
32
|
+
## V1 — Nuevo diseño
|
|
33
|
+
|
|
34
|
+
Cuando `useUtilityLoading` es `false` (default): **NewSpinner** — spinner SVG animado con Track + Arc redondeado.
|
|
35
|
+
Cuando `useUtilityLoading` es `true`: **LoaderWithLogo** — logo SVG del cliente con animación de pulso y track con gradiente.
|
|
36
|
+
|
|
37
|
+
### Props adicionales de V1 — NewSpinner
|
|
38
|
+
|
|
39
|
+
| Nombre | Tipo | Descripción |
|
|
40
|
+
| ---------- | ------ | --------------------------------------------------- |
|
|
41
|
+
| dataTestId | string | Test ID del contenedor (default: `UTLoading.spinner`) |
|
|
42
|
+
| label | string | Texto opcional debajo del spinner (ej: "Cargando...") |
|
|
43
|
+
| size | number | Tamaño del spinner en px (default: 72) |
|
|
44
|
+
| thickness | number | Grosor del Track y Arc (default: 5) |
|
|
45
|
+
|
|
46
|
+
### Props adicionales de V1 — LoaderWithLogo
|
|
47
|
+
|
|
48
|
+
| Nombre | Tipo | Descripción |
|
|
49
|
+
| ---------- | ----------- | -------------------------------------------------------------- |
|
|
50
|
+
| dataTestId | string | Test ID del contenedor (default: `UTLoading.loader`) |
|
|
51
|
+
| fullScreen | bool | Si `true`, ocupa toda la pantalla con position absolute y z-index alto |
|
|
52
|
+
| Logo | elementType | Componente SVG del logo de la utility (importado vía react-native-svg-transformer) |
|
|
53
|
+
| logoSize | number | Tamaño del logo en px (default: 56) |
|
|
54
|
+
| size | number | Tamaño del track circular en px (default: 120) |
|
|
55
|
+
| thickness | number | Grosor del track (default: 5) |
|
|
56
|
+
|
|
57
|
+
### Colores (override vía ThemeProvider)
|
|
58
|
+
|
|
59
|
+
Los colores del V1 se configuran vía `theme.UTLoading`:
|
|
60
|
+
|
|
61
|
+
| Token | Default | Descripción |
|
|
62
|
+
| ------------------ | ---------- | ------------------------------------ |
|
|
63
|
+
| `arcColor` | `#0136E7` | Color del arco del NewSpinner |
|
|
64
|
+
| `trackColor` | `#E9EFFF` | Color del track del NewSpinner |
|
|
65
|
+
| `gradientStart` | `#285AFF` | Color inicial del gradiente del Loader |
|
|
66
|
+
| `gradientEnd` | `#7AA0FF` | Color final del gradiente del Loader |
|
|
67
|
+
| `trackBackground` | `#E9EFFF` | Color del track de fondo del Loader |
|
|
68
|
+
|
|
69
|
+
## Activación desde la app (UtilityGO Office Mobile)
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
// src/config/base/config.json
|
|
73
|
+
"dashboard": {
|
|
74
|
+
"parameters": {
|
|
75
|
+
"newDashboardExperience": {
|
|
76
|
+
"parameters": {
|
|
77
|
+
"loading": { "enabled": false }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
// En cada pantalla
|
|
86
|
+
const { enabled: useNewLoading } =
|
|
87
|
+
appConfig.dashboard?.parameters?.newDashboardExperience?.parameters?.loading || {};
|
|
88
|
+
|
|
89
|
+
<UTLoading
|
|
90
|
+
version={useNewLoading ? 'V1' : 'V0'}
|
|
91
|
+
loading={isLoading}
|
|
92
|
+
Logo={UtilityLogo}
|
|
93
|
+
useUtilityLoading={useUtilityLoading}
|
|
94
|
+
/>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Ejemplo
|
|
21
98
|
|
|
22
99
|
```js
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
100
|
+
import { UTLoading } from '@widergy/mobile-ui';
|
|
101
|
+
import DemoLogo from 'config/utility/usersConfig/default/logo.svg';
|
|
102
|
+
|
|
103
|
+
// V1 — Spinner nuevo
|
|
104
|
+
<UTLoading version="V1" loading={isLoading} label="Cargando..." />
|
|
105
|
+
|
|
106
|
+
// V1 — Loader con logo fullScreen
|
|
107
|
+
<UTLoading
|
|
108
|
+
version="V1"
|
|
109
|
+
useUtilityLoading
|
|
110
|
+
fullScreen
|
|
111
|
+
loading={isLoading}
|
|
112
|
+
Logo={DemoLogo}
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
// V0 — Spinner clásico (sin cambios)
|
|
116
|
+
<UTLoading version="V0" loading={isLoading} message="Cargando..." />
|
|
39
117
|
```
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { string } from 'prop-types';
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import V0 from './versions/V0';
|
|
5
|
+
import V1 from './versions/V1';
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const { useUtilityLoading } = props || {};
|
|
9
|
-
return useUtilityLoading ? <AnimatedCircles {...props} /> : <Spinner {...props} />;
|
|
10
|
-
};
|
|
7
|
+
const VERSIONS = { V0, V1 };
|
|
11
8
|
|
|
12
|
-
UTLoading
|
|
9
|
+
const UTLoading = ({ version = 'V0', ...props }) => {
|
|
10
|
+
const Component = VERSIONS[version] || V0;
|
|
11
|
+
return <Component {...props} />;
|
|
12
|
+
};
|
|
13
13
|
|
|
14
14
|
UTLoading.propTypes = {
|
|
15
|
-
|
|
15
|
+
version: string
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export default UTLoading;
|
package/lib/components/UTLoading/{components → versions/V0/components}/AnimatedCircles/index.js
RENAMED
|
@@ -3,7 +3,7 @@ import React, { useEffect, useRef } from 'react';
|
|
|
3
3
|
import { Animated, Image, View } from 'react-native';
|
|
4
4
|
import { string, bool, node, number } from 'prop-types';
|
|
5
5
|
|
|
6
|
-
import { useTheme } from '
|
|
6
|
+
import { useTheme } from '../../../../../../theming';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
OPACITY_DURATION,
|
package/lib/components/UTLoading/{components → versions/V0/components}/AnimatedCircles/styles.js
RENAMED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import { verticalScale } from '
|
|
3
|
+
import { verticalScale } from '../../../../../../utils/scaleUtils';
|
|
4
|
+
|
|
5
|
+
const WHITE = '#ffffff';
|
|
6
|
+
const BLACK = '#000000';
|
|
4
7
|
|
|
5
8
|
export default StyleSheet.create({
|
|
9
|
+
circle: {
|
|
10
|
+
backgroundColor: BLACK,
|
|
11
|
+
borderRadius: 10,
|
|
12
|
+
height: 16,
|
|
13
|
+
margin: 4,
|
|
14
|
+
width: 16
|
|
15
|
+
},
|
|
16
|
+
circlesContainer: {
|
|
17
|
+
flexDirection: 'row',
|
|
18
|
+
marginTop: 50
|
|
19
|
+
},
|
|
6
20
|
container: {
|
|
7
21
|
alignItems: 'center',
|
|
8
|
-
backgroundColor:
|
|
22
|
+
backgroundColor: WHITE,
|
|
9
23
|
flex: 1,
|
|
10
24
|
flexDirection: 'column',
|
|
11
25
|
justifyContent: 'center',
|
|
12
26
|
width: '100%'
|
|
13
27
|
},
|
|
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
28
|
imageStyle: {
|
|
26
29
|
height: verticalScale(40)
|
|
27
30
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { number, string, bool } from 'prop-types';
|
|
3
3
|
import { View } from 'react-native';
|
|
4
4
|
import { ViewPropTypes } from 'deprecated-react-native-prop-types';
|
|
5
5
|
|
|
6
|
-
import Loading from '
|
|
6
|
+
import Loading from '../../../../../Loading';
|
|
7
7
|
|
|
8
8
|
import styles from './styles';
|
|
9
9
|
|
|
@@ -19,7 +19,7 @@ const Spinner = ({
|
|
|
19
19
|
thickness
|
|
20
20
|
}) => {
|
|
21
21
|
return (
|
|
22
|
-
|
|
22
|
+
<>
|
|
23
23
|
{!!loading && (
|
|
24
24
|
<Loading
|
|
25
25
|
style={[styles.spinner, style]}
|
|
@@ -36,7 +36,7 @@ const Spinner = ({
|
|
|
36
36
|
) : (
|
|
37
37
|
!loading && children
|
|
38
38
|
)}
|
|
39
|
-
|
|
39
|
+
</>
|
|
40
40
|
);
|
|
41
41
|
};
|
|
42
42
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { bool } from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import AnimatedCircles from './components/AnimatedCircles';
|
|
5
|
+
import Spinner from './components/Spinner';
|
|
6
|
+
|
|
7
|
+
const UTLoading = props => {
|
|
8
|
+
const { useUtilityLoading } = props || {};
|
|
9
|
+
return useUtilityLoading ? <AnimatedCircles {...props} /> : <Spinner {...props} />;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
UTLoading.displayName = 'UTLoading';
|
|
13
|
+
|
|
14
|
+
UTLoading.propTypes = {
|
|
15
|
+
useUtilityLoading: bool
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default UTLoading;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { Animated, Easing, View } from 'react-native';
|
|
3
|
+
import { bool, elementType, node, number, string } from 'prop-types';
|
|
4
|
+
|
|
5
|
+
import UTLabel from '../../../../../UTLabel';
|
|
6
|
+
import { TEST_IDS } from '../../../../../../constants/testIds';
|
|
7
|
+
|
|
8
|
+
import { ownStyles } from './theme';
|
|
9
|
+
|
|
10
|
+
const { UTLoading: loadingIds } = TEST_IDS;
|
|
11
|
+
|
|
12
|
+
const LoaderWithLogo = ({
|
|
13
|
+
children,
|
|
14
|
+
dataTestId = loadingIds.loader,
|
|
15
|
+
fullScreen = false,
|
|
16
|
+
loading,
|
|
17
|
+
LoaderRing,
|
|
18
|
+
Logo,
|
|
19
|
+
logoSize,
|
|
20
|
+
message,
|
|
21
|
+
rotationDuration,
|
|
22
|
+
size
|
|
23
|
+
}) => {
|
|
24
|
+
const rotation = useRef(new Animated.Value(0)).current;
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
Animated.loop(
|
|
28
|
+
Animated.timing(rotation, {
|
|
29
|
+
duration: rotationDuration,
|
|
30
|
+
easing: Easing.linear,
|
|
31
|
+
toValue: 1,
|
|
32
|
+
useNativeDriver: false
|
|
33
|
+
})
|
|
34
|
+
).start();
|
|
35
|
+
}, [rotation, rotationDuration]);
|
|
36
|
+
|
|
37
|
+
if (!loading) return children ?? null;
|
|
38
|
+
|
|
39
|
+
const spin = rotation.interpolate({
|
|
40
|
+
inputRange: [0, 1],
|
|
41
|
+
outputRange: ['0deg', '360deg']
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const containerStyle = fullScreen ? ownStyles.fullScreen : ownStyles.container;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<View style={containerStyle} testID={dataTestId}>
|
|
48
|
+
<View style={[ownStyles.ringWrapper, { height: size, width: size }]}>
|
|
49
|
+
{!!LoaderRing && (
|
|
50
|
+
<Animated.View style={[ownStyles.ringAbsolute, { transform: [{ rotate: spin }] }]}>
|
|
51
|
+
<LoaderRing height={size} width={size} />
|
|
52
|
+
</Animated.View>
|
|
53
|
+
)}
|
|
54
|
+
{!!Logo && (
|
|
55
|
+
<View style={ownStyles.logoWrapper}>
|
|
56
|
+
<Logo height={logoSize} width={logoSize} />
|
|
57
|
+
</View>
|
|
58
|
+
)}
|
|
59
|
+
</View>
|
|
60
|
+
{!!message && (
|
|
61
|
+
<UTLabel style={ownStyles.message} variant="small">
|
|
62
|
+
{message}
|
|
63
|
+
</UTLabel>
|
|
64
|
+
)}
|
|
65
|
+
</View>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
LoaderWithLogo.displayName = 'UTLoading';
|
|
70
|
+
|
|
71
|
+
LoaderWithLogo.propTypes = {
|
|
72
|
+
children: node,
|
|
73
|
+
dataTestId: string,
|
|
74
|
+
fullScreen: bool,
|
|
75
|
+
loading: bool,
|
|
76
|
+
LoaderRing: elementType,
|
|
77
|
+
Logo: elementType,
|
|
78
|
+
logoSize: number,
|
|
79
|
+
message: string,
|
|
80
|
+
rotationDuration: number,
|
|
81
|
+
size: number
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default LoaderWithLogo;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
const WHITE = '#ffffff';
|
|
4
|
+
|
|
5
|
+
export const ownStyles = StyleSheet.create({
|
|
6
|
+
container: {
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
backgroundColor: WHITE,
|
|
9
|
+
flex: 1,
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
width: '100%'
|
|
12
|
+
},
|
|
13
|
+
fullScreen: {
|
|
14
|
+
alignItems: 'center',
|
|
15
|
+
backgroundColor: WHITE,
|
|
16
|
+
bottom: 0,
|
|
17
|
+
elevation: 9999,
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
left: 0,
|
|
20
|
+
position: 'absolute',
|
|
21
|
+
right: 0,
|
|
22
|
+
top: 0,
|
|
23
|
+
zIndex: 9999
|
|
24
|
+
},
|
|
25
|
+
logoWrapper: {
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
bottom: 0,
|
|
28
|
+
justifyContent: 'center',
|
|
29
|
+
left: 0,
|
|
30
|
+
position: 'absolute',
|
|
31
|
+
right: 0,
|
|
32
|
+
top: 0
|
|
33
|
+
},
|
|
34
|
+
message: {
|
|
35
|
+
marginTop: 12,
|
|
36
|
+
textAlign: 'center'
|
|
37
|
+
},
|
|
38
|
+
ringAbsolute: {
|
|
39
|
+
position: 'absolute'
|
|
40
|
+
},
|
|
41
|
+
ringWrapper: {
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
justifyContent: 'center'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { Animated, Easing, View } from 'react-native';
|
|
3
|
+
import { arrayOf, bool, node, number, string } from 'prop-types';
|
|
4
|
+
import { ViewPropTypes } from 'deprecated-react-native-prop-types';
|
|
5
|
+
import { Circle, Defs, LinearGradient, Stop, Svg } from 'react-native-svg';
|
|
6
|
+
|
|
7
|
+
import { useTheme } from '../../../../../../theming';
|
|
8
|
+
import UTLabel from '../../../../../UTLabel';
|
|
9
|
+
import { TEST_IDS } from '../../../../../../constants/testIds';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
ARC_SWEEP_DEGREES,
|
|
13
|
+
GRADIENT_ID,
|
|
14
|
+
SPINNER_ROTATION_DURATION,
|
|
15
|
+
SPINNER_SIZE,
|
|
16
|
+
SPINNER_THICKNESS
|
|
17
|
+
} from './constants';
|
|
18
|
+
import {
|
|
19
|
+
getArcColor,
|
|
20
|
+
getRadius,
|
|
21
|
+
getSpinnerSize,
|
|
22
|
+
getSpinnerThickness,
|
|
23
|
+
getTrackColor,
|
|
24
|
+
ownStyles
|
|
25
|
+
} from './theme';
|
|
26
|
+
|
|
27
|
+
const AnimatedSvg = Animated.createAnimatedComponent(Svg);
|
|
28
|
+
|
|
29
|
+
const { UTLoading: loadingIds } = TEST_IDS;
|
|
30
|
+
|
|
31
|
+
const renderArc = (spinnerSize, radius, arcColor, spinnerThickness, arcLength, circumference, colors) => {
|
|
32
|
+
const isGradient = colors?.length === 2;
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
{isGradient && (
|
|
36
|
+
<Defs>
|
|
37
|
+
<LinearGradient id={GRADIENT_ID} x1="0" y1="0" x2="1" y2="0">
|
|
38
|
+
<Stop offset="0" stopColor={colors[0]} />
|
|
39
|
+
<Stop offset="1" stopColor={colors[1]} />
|
|
40
|
+
</LinearGradient>
|
|
41
|
+
</Defs>
|
|
42
|
+
)}
|
|
43
|
+
<Circle
|
|
44
|
+
cx={spinnerSize / 2}
|
|
45
|
+
cy={spinnerSize / 2}
|
|
46
|
+
r={radius}
|
|
47
|
+
stroke={isGradient ? `url(#${GRADIENT_ID})` : arcColor}
|
|
48
|
+
strokeWidth={spinnerThickness}
|
|
49
|
+
strokeLinecap="round"
|
|
50
|
+
strokeDasharray={`${arcLength} ${circumference - arcLength}`}
|
|
51
|
+
strokeDashoffset={0}
|
|
52
|
+
fill="none"
|
|
53
|
+
/>
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const Spinner = ({
|
|
59
|
+
children,
|
|
60
|
+
colors,
|
|
61
|
+
dataTestId = loadingIds.spinner,
|
|
62
|
+
loading,
|
|
63
|
+
message,
|
|
64
|
+
preventUnmount,
|
|
65
|
+
size = SPINNER_SIZE,
|
|
66
|
+
style,
|
|
67
|
+
thickness = SPINNER_THICKNESS
|
|
68
|
+
}) => {
|
|
69
|
+
const theme = useTheme();
|
|
70
|
+
const rotation = useRef(new Animated.Value(0)).current;
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
Animated.loop(
|
|
74
|
+
Animated.timing(rotation, {
|
|
75
|
+
duration: SPINNER_ROTATION_DURATION,
|
|
76
|
+
easing: Easing.linear,
|
|
77
|
+
toValue: 1,
|
|
78
|
+
useNativeDriver: true
|
|
79
|
+
})
|
|
80
|
+
).start();
|
|
81
|
+
}, [rotation]);
|
|
82
|
+
|
|
83
|
+
if (!loading && !preventUnmount) return children ?? null;
|
|
84
|
+
|
|
85
|
+
const spinnerSize = getSpinnerSize(size);
|
|
86
|
+
const spinnerThickness = getSpinnerThickness(thickness);
|
|
87
|
+
const radius = getRadius(size, thickness);
|
|
88
|
+
const circumference = 2 * Math.PI * radius;
|
|
89
|
+
const arcLength = (ARC_SWEEP_DEGREES / 360) * circumference;
|
|
90
|
+
const trackColor = getTrackColor(theme);
|
|
91
|
+
const arcColor = colors?.length >= 1 ? colors[0] : getArcColor(theme);
|
|
92
|
+
|
|
93
|
+
const spin = rotation.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] });
|
|
94
|
+
|
|
95
|
+
const spinnerContent = (
|
|
96
|
+
<View style={[ownStyles.container, style]} testID={dataTestId}>
|
|
97
|
+
<AnimatedSvg width={spinnerSize} height={spinnerSize} style={{ transform: [{ rotate: spin }] }}>
|
|
98
|
+
<Circle
|
|
99
|
+
cx={spinnerSize / 2}
|
|
100
|
+
cy={spinnerSize / 2}
|
|
101
|
+
r={radius}
|
|
102
|
+
stroke={trackColor}
|
|
103
|
+
strokeWidth={spinnerThickness}
|
|
104
|
+
fill="none"
|
|
105
|
+
/>
|
|
106
|
+
{renderArc(spinnerSize, radius, arcColor, spinnerThickness, arcLength, circumference, colors)}
|
|
107
|
+
</AnimatedSvg>
|
|
108
|
+
{!!message && (
|
|
109
|
+
<UTLabel style={ownStyles.message} variant="small">
|
|
110
|
+
{message}
|
|
111
|
+
</UTLabel>
|
|
112
|
+
)}
|
|
113
|
+
</View>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if (preventUnmount) {
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
{!!loading && spinnerContent}
|
|
120
|
+
{/* eslint-disable-next-line react-native/no-inline-styles */}
|
|
121
|
+
<View style={{ display: loading ? 'none' : 'flex' }}>{children}</View>
|
|
122
|
+
</>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return spinnerContent;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
Spinner.displayName = 'UTLoading';
|
|
130
|
+
|
|
131
|
+
Spinner.propTypes = {
|
|
132
|
+
children: node,
|
|
133
|
+
colors: arrayOf(string),
|
|
134
|
+
dataTestId: string,
|
|
135
|
+
loading: bool,
|
|
136
|
+
message: string,
|
|
137
|
+
preventUnmount: bool,
|
|
138
|
+
style: ViewPropTypes.style,
|
|
139
|
+
size: number,
|
|
140
|
+
thickness: number
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export default Spinner;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SPINNER_SIZE, SPINNER_THICKNESS } from './constants';
|
|
2
|
+
|
|
3
|
+
export const ownStyles = {
|
|
4
|
+
container: {
|
|
5
|
+
alignItems: 'center',
|
|
6
|
+
flex: 1,
|
|
7
|
+
justifyContent: 'center'
|
|
8
|
+
},
|
|
9
|
+
message: {
|
|
10
|
+
marginTop: 12,
|
|
11
|
+
textAlign: 'center'
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const getSpinnerSize = size => size || SPINNER_SIZE;
|
|
16
|
+
|
|
17
|
+
export const getSpinnerThickness = thickness => thickness || SPINNER_THICKNESS;
|
|
18
|
+
|
|
19
|
+
export const getRadius = (size, thickness) => (getSpinnerSize(size) - getSpinnerThickness(thickness)) / 2;
|
|
20
|
+
|
|
21
|
+
export const getArcColor = theme => theme?.UTLoading?.arcColor || theme?.colors?.primary;
|
|
22
|
+
|
|
23
|
+
export const getTrackColor = theme => theme?.UTLoading?.trackColor || theme?.Palette?.light?.['04'];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { arrayOf, bool, elementType, node, number, string } from 'prop-types';
|
|
3
|
+
import { ViewPropTypes } from 'deprecated-react-native-prop-types';
|
|
4
|
+
|
|
5
|
+
import LoaderWithLogo from './components/LoaderWithLogo';
|
|
6
|
+
import Spinner from './components/Spinner';
|
|
7
|
+
|
|
8
|
+
const UTLoading = props => {
|
|
9
|
+
const { useUtilityLoading } = props || {};
|
|
10
|
+
return useUtilityLoading ? <LoaderWithLogo {...props} /> : <Spinner {...props} />;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
UTLoading.displayName = 'UTLoading';
|
|
14
|
+
|
|
15
|
+
UTLoading.propTypes = {
|
|
16
|
+
children: node,
|
|
17
|
+
colors: arrayOf(string),
|
|
18
|
+
dataTestId: string,
|
|
19
|
+
fullScreen: bool,
|
|
20
|
+
loading: bool,
|
|
21
|
+
LoaderRing: elementType,
|
|
22
|
+
Logo: elementType,
|
|
23
|
+
logoSize: number,
|
|
24
|
+
message: string,
|
|
25
|
+
preventUnmount: bool,
|
|
26
|
+
rotationDuration: number,
|
|
27
|
+
size: number,
|
|
28
|
+
style: ViewPropTypes.style,
|
|
29
|
+
thickness: number,
|
|
30
|
+
useUtilityLoading: bool
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default UTLoading;
|
package/lib/constants/testIds.js
CHANGED
|
@@ -19,6 +19,7 @@ export const TEST_ID_CONSTANTS = {
|
|
|
19
19
|
label: 'label',
|
|
20
20
|
left: 'left',
|
|
21
21
|
list: 'list',
|
|
22
|
+
loader: 'loader',
|
|
22
23
|
logo: 'logo',
|
|
23
24
|
modal: 'modal',
|
|
24
25
|
option: 'option',
|
|
@@ -30,6 +31,7 @@ export const TEST_ID_CONSTANTS = {
|
|
|
30
31
|
searchInput: 'searchInput',
|
|
31
32
|
secondaryAction: 'secondaryAction',
|
|
32
33
|
selectAll: 'selectAll',
|
|
34
|
+
spinner: 'spinner',
|
|
33
35
|
subLabel: 'subLabel',
|
|
34
36
|
subtitle: 'subtitle',
|
|
35
37
|
tagline: 'tagline',
|
|
@@ -59,6 +61,10 @@ export const TEST_IDS = {
|
|
|
59
61
|
},
|
|
60
62
|
roundView: 'roundView',
|
|
61
63
|
skeletonLoader: 'skeletonLoader',
|
|
64
|
+
UTLoading: {
|
|
65
|
+
loader: `UTLoading.${TEST_ID_CONSTANTS.loader}`,
|
|
66
|
+
spinner: `UTLoading.${TEST_ID_CONSTANTS.spinner}`
|
|
67
|
+
},
|
|
62
68
|
topbar: {
|
|
63
69
|
goBack: 'topbar.goBack',
|
|
64
70
|
title: 'topbar.title'
|
package/package.json
CHANGED
/package/lib/components/UTLoading/{components → versions/V0/components}/AnimatedCircles/constants.js
RENAMED
|
File without changes
|