@widergy/mobile-ui 1.34.0 → 1.36.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.36.0](https://github.com/widergy/mobile-ui/compare/v1.35.0...v1.36.0) (2025-02-03)
2
+
3
+
4
+ ### Features
5
+
6
+ * [EVENSA-67] uttabs ([#409](https://github.com/widergy/mobile-ui/issues/409)) ([e82a497](https://github.com/widergy/mobile-ui/commit/e82a49721c179c63fef5cbfe7d61eaed172476d0))
7
+
8
+ # [1.35.0](https://github.com/widergy/mobile-ui/compare/v1.34.0...v1.35.0) (2025-01-31)
9
+
10
+
11
+ ### Features
12
+
13
+ * added util for generating Flow Id's ([5db21ef](https://github.com/widergy/mobile-ui/commit/5db21ef0002558c272641928ea80e94c6ee85ce0))
14
+
1
15
  # [1.34.0](https://github.com/widergy/mobile-ui/compare/v1.33.4...v1.34.0) (2025-01-27)
2
16
 
3
17
 
@@ -41,7 +41,7 @@ export default StyleSheet.create({
41
41
  alignItems: 'center',
42
42
  display: 'flex',
43
43
  gap: 24,
44
- width: '100%'
44
+ width: 'auto'
45
45
  },
46
46
  section: {
47
47
  alignItems: 'center',
@@ -0,0 +1,41 @@
1
+ # UTTabs
2
+
3
+ Tabs component.
4
+
5
+ ## Props
6
+ Here's a new table for the additional props:
7
+
8
+ | Name | Type | Default | Description |
9
+ |------------|---------|------------|-----------------------------------------------------------|
10
+ | colorTheme | string | `accent` | Defines the color theme for the component. |
11
+ | hierarchy | string | `primary` | Determines the hierarchy or importance of the tabs. |
12
+ | onChange | func | | Callback function triggered when the selected tab changes.|
13
+ | style | object | | Custom styles for component. |
14
+ | tabs | array | | Array of tab items to be displayed within the component. |
15
+ | withTabSliding | bool | `true` | Defines if tabs can be changed with gesture. |
16
+
17
+
18
+ ### colorTheme
19
+
20
+ The value of `colorTheme` must be one of the following:
21
+
22
+ - `accent`
23
+ - `negative`
24
+ - `neutral`
25
+
26
+ ### hierarchy
27
+
28
+ The value of `hierarchy` must be one of the following:
29
+
30
+ - `primary`
31
+ - `secondary`
32
+
33
+ ### tabs
34
+
35
+ `tabs` is an array of object with the following optional props:
36
+
37
+ - `label`: text to render
38
+ - `icon`: name of `UTIcon` to render
39
+ - `badge`: not affected by `colorTheme`
40
+
41
+ Besides those, any other prop can be added to a tab to be accessed with the `onChange` callback
@@ -0,0 +1,10 @@
1
+ export const HIERARCHIES = {
2
+ PRIMARY: 'primary',
3
+ SECONDARY: 'secondary'
4
+ };
5
+
6
+ export const COLOR_THEMES = {
7
+ ACCENT: 'accent',
8
+ NEGATIVE: 'negative',
9
+ NEUTRAL: 'neutral'
10
+ };
@@ -0,0 +1,86 @@
1
+ import { Animated, View, Pressable, PanResponder } from 'react-native';
2
+ import { array, bool, func, object, string } from 'prop-types';
3
+ import React, { useEffect, useRef, useState } from 'react';
4
+
5
+ import { withTheme } from '../../theming';
6
+ import UTBadge from '../UTBadge';
7
+ import UTIcon from '../UTIcon';
8
+ import UTLabel from '../UTLabel';
9
+
10
+ import styleSheet from './styles';
11
+ import { COLOR_THEMES, HIERARCHIES } from './constants';
12
+
13
+ const UTTabs = ({
14
+ colorTheme = COLOR_THEMES.ACCENT,
15
+ hierarchy = HIERARCHIES.SECONDARY,
16
+ onChange,
17
+ style,
18
+ tabs,
19
+ theme,
20
+ withTabSliding = true
21
+ }) => {
22
+ const styles = styleSheet(theme);
23
+ const [selectedTab, setSelectedTab] = useState(0);
24
+ const position = useRef(new Animated.Value(0)).current;
25
+
26
+ useEffect(() => {
27
+ onChange?.(tabs[selectedTab]);
28
+ }, []);
29
+
30
+ useEffect(() => {
31
+ Animated.timing(position, {
32
+ toValue: selectedTab,
33
+ duration: 300
34
+ }).start();
35
+ onChange?.(tabs[selectedTab]);
36
+ }, [selectedTab]);
37
+
38
+ const panResponder = useRef(
39
+ PanResponder.create({
40
+ onMoveShouldSetPanResponder: (_, gestureState) => Math.abs(gestureState.dx),
41
+ onPanResponderRelease: (_, gestureState) => {
42
+ if (gestureState.dx > 1) setSelectedTab(prev => Math.max(0, prev - 1));
43
+ else if (gestureState.dx < -1) {
44
+ setSelectedTab(prev => Math.min(tabs.length - 1, prev + 1));
45
+ }
46
+ }
47
+ })
48
+ ).current;
49
+
50
+ return (
51
+ <View style={[styles.container, style]} {...(withTabSliding ? panResponder.panHandlers : {})}>
52
+ {tabs.map(({ badge, label, icon }, index) => {
53
+ const selected = selectedTab === index;
54
+ const colorThemeToUse = selected ? colorTheme : 'gray';
55
+ return (
56
+ <Pressable
57
+ disabled={selected}
58
+ key={`tab-${label || icon}`}
59
+ onPress={() => setSelectedTab(index)}
60
+ style={styles.tab(tabs.length)}
61
+ >
62
+ <UTIcon colorTheme={colorThemeToUse} name={icon} />
63
+ <UTLabel colorTheme={colorThemeToUse} shade="04" weight="medium">
64
+ {label}
65
+ </UTLabel>
66
+ {badge && <UTBadge colorTheme="accent" />}
67
+ </Pressable>
68
+ );
69
+ })}
70
+ <Animated.View style={styles.indicator(position, tabs.length, hierarchy, colorTheme)} />
71
+ <View style={styles.border} />
72
+ </View>
73
+ );
74
+ };
75
+
76
+ UTTabs.propTypes = {
77
+ colorTheme: string,
78
+ hierarchy: string,
79
+ onChange: func,
80
+ style: object,
81
+ tabs: array,
82
+ theme: object,
83
+ withTabSliding: bool
84
+ };
85
+
86
+ export default withTheme(UTTabs);
@@ -0,0 +1,82 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { COLOR_THEMES, HIERARCHIES } from './constants';
4
+
5
+ export default StyleSheet.create(({ Palette: { accent, neutral, negative, light } }) => ({
6
+ border: {
7
+ position: 'absolute',
8
+ bottom: 0,
9
+ width: '100%',
10
+ height: 1,
11
+ backgroundColor: light['04'],
12
+ zIndex: 1
13
+ },
14
+ container: { display: 'flex', flexDirection: 'row', width: '100%' },
15
+ indicator: (position, length, hierarchy, colorTheme) =>
16
+ ({
17
+ [HIERARCHIES.PRIMARY]: {
18
+ position: 'absolute',
19
+ bottom: 0,
20
+ width: `${100 / length}%`,
21
+ height: '100%',
22
+ borderRightWidth: position.interpolate({
23
+ inputRange: [0, length - 1],
24
+ outputRange: [1, 0]
25
+ }),
26
+ borderTopRightRadius: position.interpolate({
27
+ inputRange: [0, length - 1],
28
+ outputRange: [4, 0]
29
+ }),
30
+ borderLeftWidth: position.interpolate({
31
+ inputRange: [0, 1],
32
+ outputRange: [0, 1],
33
+ extrapolate: 'clamp'
34
+ }),
35
+ borderTopLeftRadius: position.interpolate({
36
+ inputRange: [0, 1],
37
+ outputRange: [0, 4],
38
+ extrapolate: 'clamp'
39
+ }),
40
+ backgroundColor: light['01'],
41
+ borderTopWidth: 1,
42
+ borderTopColor: light['04'],
43
+ borderLeftColor: light['04'],
44
+ borderRightColor: light['04'],
45
+ borderBottomWidth: 1,
46
+ borderBottomColor: light['01'],
47
+ left: position.interpolate({
48
+ inputRange: [0, length],
49
+ outputRange: ['0%', '100%']
50
+ }),
51
+ zIndex: 2
52
+ },
53
+ [HIERARCHIES.SECONDARY]: {
54
+ position: 'absolute',
55
+ bottom: 0,
56
+ width: `${100 / length}%`,
57
+ height: 4,
58
+ backgroundColor: {
59
+ [COLOR_THEMES.ACCENT]: accent['04'],
60
+ [COLOR_THEMES.NEUTRAL]: neutral['04'],
61
+ [COLOR_THEMES.NEGATIVE]: negative['04']
62
+ }[colorTheme],
63
+ left: position.interpolate({
64
+ inputRange: [0, length],
65
+ outputRange: ['0%', '100%']
66
+ })
67
+ }
68
+ })[hierarchy],
69
+ tab:
70
+ tabs =>
71
+ ({ pressed }) => ({
72
+ alignItems: 'center',
73
+ display: 'flex',
74
+ flexBasis: `${100 / tabs}%`,
75
+ flexDirection: 'row',
76
+ gap: 8,
77
+ height: 48,
78
+ justifyContent: 'center',
79
+ zIndex: 3,
80
+ backgroundColor: pressed ? accent['01'] : null
81
+ })
82
+ }));
package/lib/index.js CHANGED
@@ -65,6 +65,7 @@ export { default as UTSelectableCard } from './components/UTSelectableCard';
65
65
  export { default as UTStatusMessage } from './components/UTStatusMessage';
66
66
  export { default as UTStepFeedback } from './components/UTStepFeedback';
67
67
  export { default as UTSwitch } from './components/UTSwitch';
68
+ export { default as UTTabs } from './components/UTTabs';
68
69
  export { default as UTTextArea } from './components/UTTextArea';
69
70
  export { default as UTTextInput } from './components/UTTextInput';
70
71
  export { default as UTTooltip } from './components/UTTooltip';
@@ -59,6 +59,27 @@ export const store = createStore(
59
59
  );
60
60
  ```
61
61
 
62
+ ## `analyticsUtils.generateFlowId`
63
+
64
+ Generates a `flowId` that can be used to track a user's flow through the app (To either identify the session or the user's device).
65
+
66
+ ### Type: `:string()`
67
+
68
+ ### Params
69
+
70
+ No params required.
71
+
72
+ #### Example
73
+
74
+ ```js
75
+ import { generateFlowId } from '@widergy/mobile-ui';
76
+
77
+ const handleSessionTimeout = () => {
78
+ const flowId = generateFlowId();
79
+ dispatch({ type: 'SET_SESSION_FLOW_ID', payload: { flowId } });
80
+ }
81
+ ```
82
+
62
83
  ## `analyticsUtils.tracker`
63
84
 
64
85
  Implemented inside the `middleware` returned by `analyticsUtils.createAnalyticsMiddleware`. Can be used individually to track events outside of redux.
@@ -5,6 +5,7 @@
5
5
  * */
6
6
 
7
7
  import { isEmpty, merge } from 'lodash';
8
+ import uuid from 'react-native-uuid';
8
9
 
9
10
  const LOG_EVENT = 'LOG_EVENT';
10
11
  const SET_CURRENT_SCREEN = 'SET_CURRENT_SCREEN';
@@ -146,8 +147,13 @@ export const intercomUpdateUser = intercomInstance => userProperties => {
146
147
  if (intercomInstance) intercomInstance.updateUser(userProperties);
147
148
  };
148
149
 
150
+ export const generateFlowId = () => {
151
+ return uuid.v4();
152
+ };
153
+
149
154
  export default {
150
155
  createAnalyticsMiddleware,
156
+ generateFlowId,
151
157
  intercomSingleEvent,
152
158
  intercomUpdateUser,
153
159
  mixpanelEventsFlush,
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.34.0",
5
+ "version": "1.36.0",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [
@@ -48,9 +48,10 @@
48
48
  "react-native-linear-gradient": "^2.8.3",
49
49
  "react-native-markdown-display": "^7.0.0-alpha.2",
50
50
  "react-native-modal": "^13.0.1",
51
- "react-native-pager-view": "^6.2.1",
51
+ "react-native-pager-view": "^6.2.0",
52
52
  "react-native-safe-area-context": "^4.5.0",
53
- "react-native-svg": "^13.13.0"
53
+ "react-native-svg": "^13.0.0",
54
+ "react-native-uuid": "^2.0.3"
54
55
  },
55
56
  "devDependencies": {
56
57
  "@babel/cli": "^7.22.10",