@widergy/mobile-ui 1.37.0 → 1.38.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,10 @@
1
+ # [1.38.0](https://github.com/widergy/mobile-ui/compare/v1.37.0...v1.38.0) (2025-03-26)
2
+
3
+
4
+ ### Features
5
+
6
+ * [EVENSA-155] data item & data category ([#415](https://github.com/widergy/mobile-ui/issues/415)) ([7c76dee](https://github.com/widergy/mobile-ui/commit/7c76dee1b60c2d730da91064382b0dbcde144543))
7
+
1
8
  # [1.37.0](https://github.com/widergy/mobile-ui/compare/v1.36.8...v1.37.0) (2025-03-19)
2
9
 
3
10
 
@@ -18,7 +18,7 @@ const BottomActions = ({ actions = [], bottomActionsVariant }) => {
18
18
 
19
19
  return (
20
20
  <View style={[themedStyles.actionsContainer, themedStyles.redirectionActionsContainer]}>
21
- {actions.map(({ colorTheme = 'primary', disabled, Icon, label, loading, onClick }, i) => (
21
+ {actions.map(({ colorTheme = 'primary', disabled, Icon, label, loading, onPress }, i) => (
22
22
  <Fragment key={label}>
23
23
  {!isRedirection && i > 0 && <View style={[themedStyles.horizontalSeparator]} />}
24
24
  <UTButton
@@ -31,7 +31,7 @@ const BottomActions = ({ actions = [], bottomActionsVariant }) => {
31
31
  Icon={isRedirection ? Icon || DEFAULT_REDIRECTION_ICON : Icon}
32
32
  iconPlacement={isRedirection ? 'right' : 'left'}
33
33
  loading={loading}
34
- onClick={onClick}
34
+ onPress={onPress}
35
35
  size="large"
36
36
  variant="text"
37
37
  >
@@ -54,7 +54,7 @@ BottomActions.propTypes = {
54
54
  Icon: oneOfType([elementType, string]),
55
55
  label: string,
56
56
  loading: bool,
57
- onClick: func
57
+ onPress: func
58
58
  })
59
59
  ),
60
60
  bottomActionsVariant: string
@@ -0,0 +1,22 @@
1
+ # UTDataCategory
2
+
3
+ Tabs component.
4
+
5
+ ## Props
6
+
7
+
8
+ | Name | Type | Default | Description |
9
+ |------------|----------|---------|----------------------------------------------------------|
10
+ | area | bool | `false` | Specifies whether the component has an area. |
11
+ | collapsable | bool | `true` | Specifies if the data list is collapsable |
12
+ | elements | array | | Array of items to be rendered as UTDataElement |
13
+ | style | object | | Custom style for the component container. |
14
+ | title | string | | Title text displayed in the component. |
15
+ | titleProps | object | | Additional props for customizing the title. |
16
+
17
+
18
+
19
+ ### colapsable
20
+
21
+ The component is only collapsable if it has a title
22
+
@@ -0,0 +1,67 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ import { Animated, View } from 'react-native';
3
+ import { array, bool, object, string } from 'prop-types';
4
+ import React, { useCallback, useRef, useState } from 'react';
5
+
6
+ import { withTheme } from '../../theming';
7
+ import UTDataElement from '../UTDataElement';
8
+ import UTLabel from '../UTLabel';
9
+ import UTButton from '../UTButton';
10
+
11
+ import styleSheet from './styles';
12
+
13
+ const UTDataCategory = ({ area, collapsable = true, elements, style, theme, title, titleProps }) => {
14
+ const styles = styleSheet(theme);
15
+
16
+ const collapsed = useRef(new Animated.Value(1)).current;
17
+ const [childrenHeight, setChildrenHeight] = useState(0);
18
+
19
+ const onLayout = useCallback(event => {
20
+ const { height } = event.nativeEvent.layout;
21
+ setChildrenHeight(height + (title ? 16 : 0));
22
+ }, []);
23
+
24
+ const toggleCollapsed = () => {
25
+ Animated.timing(collapsed, {
26
+ toValue: collapsed.__getValue() === 1 ? 0 : 1,
27
+ duration: 300,
28
+ useNativeDriver: false
29
+ }).start();
30
+ };
31
+
32
+ return (
33
+ <View style={[styles.container(area), style]}>
34
+ {title && (
35
+ <View style={[styles.title]}>
36
+ <UTLabel colorTheme="gray" weight="medium" {...titleProps}>
37
+ {title}
38
+ </UTLabel>
39
+ {collapsable && (
40
+ <Animated.View style={styles.collapseButton(collapsed)}>
41
+ <UTButton Icon="IconChevronDown" variant="text" onPress={toggleCollapsed} />
42
+ </Animated.View>
43
+ )}
44
+ </View>
45
+ )}
46
+ <Animated.View style={[styles.childrenAnimation(collapsed, childrenHeight)]}>
47
+ <View style={styles.childrenContainer} onLayout={onLayout}>
48
+ {elements.map(element => (
49
+ <UTDataElement {...element} key={element.key} />
50
+ ))}
51
+ </View>
52
+ </Animated.View>
53
+ </View>
54
+ );
55
+ };
56
+
57
+ UTDataCategory.propTypes = {
58
+ area: bool,
59
+ collapsable: bool,
60
+ elements: array,
61
+ style: object,
62
+ theme: object,
63
+ title: string,
64
+ titleProps: object
65
+ };
66
+
67
+ export default withTheme(UTDataCategory);
@@ -0,0 +1,54 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create(({ Palette: { light } }) => ({
4
+ childrenAnimation: (collapsed, childrenHeight) => ({
5
+ position: 'relative',
6
+ overflow: 'hidden',
7
+ height: collapsed.interpolate({
8
+ inputRange: [0, 1],
9
+ outputRange: [0, childrenHeight]
10
+ }),
11
+ width: 'auto'
12
+ }),
13
+ childrenContainer: {
14
+ bottom: 0,
15
+ display: 'flex',
16
+ flexDirection: 'column',
17
+ position: 'absolute',
18
+ width: '100%'
19
+ },
20
+ collapseButton: collapsed => ({
21
+ borderRadius: collapsed.interpolate({
22
+ inputRange: [0, 0.5, 1],
23
+ outputRange: [0, 100, 0]
24
+ }),
25
+ overflow: 'hidden',
26
+ transform: [
27
+ {
28
+ rotate: collapsed.interpolate({
29
+ inputRange: [0, 1],
30
+ outputRange: ['0deg', '180deg']
31
+ })
32
+ }
33
+ ]
34
+ }),
35
+ container: area => ({
36
+ display: 'flex',
37
+ flexDirection: 'column',
38
+ width: '100%',
39
+ ...(area
40
+ ? {
41
+ backgroundColor: light['03'],
42
+ padding: 16,
43
+ borderRadius: 8
44
+ }
45
+ : {})
46
+ }),
47
+ title: {
48
+ alignItems: 'center',
49
+ display: 'flex',
50
+ flexDirection: 'row',
51
+ gap: 8,
52
+ width: '100%'
53
+ }
54
+ }));
@@ -0,0 +1,46 @@
1
+ # UTDataElement
2
+
3
+ Is a versatile data component that can be customized with various themes, sizes, icons, data elements and actions.
4
+
5
+ ## Props
6
+
7
+
8
+ | Name | Type | Default | Description |
9
+ |------------|----------|---------|----------------------------------------------------------|
10
+ | action | object | | Props passed to the UTButton action . |
11
+ | area | bool | `false` | Specifies whether the component has an area. |
12
+ | badge | string | | Displays a badge with text. |
13
+ | badgeProps | object | | Additional props for customizing the badge. |
14
+ | Data | element | | React element representing a data component (overrides data). |
15
+ | data | string | | Data string associated with the component. |
16
+ | dataProps | object | | Additional props for configuring data element. |
17
+ | Icon | element | | Custom React element (overrides icon). |
18
+ | icon | string | | Name of the icon used in the component. |
19
+ | iconProps | object | | Additional props for the icon element. |
20
+ | orientation | string | `horizontal` | Defines the layout orientation. |
21
+ | padding | string | `medium` | Padding applied to the component. |
22
+ | prefix | string | | Text or symbol displayed before the title. |
23
+ | prefixProps| object | | Additional props for customizing `prefix`. |
24
+ | spacing | string | `medium` | Defines the spacing between elements. |
25
+ | style | object | | Custom style for the component container. |
26
+ | title | string | | Title text displayed in the component. |
27
+ | titleProps | object | | Additional props for customizing the title. |
28
+
29
+
30
+ ### colapsable
31
+
32
+ If the component has any `children` it will always be collapsable
33
+
34
+ ### orientation
35
+
36
+ The value of `orientation` must be one of the following:
37
+
38
+ - `horizontal`
39
+ - `vertical`
40
+
41
+ ### padding & spacing
42
+
43
+ The value of `padding` and `spacing` must be one of the following:
44
+
45
+ - `small`
46
+ - `medium`
@@ -0,0 +1,14 @@
1
+ export const ORIENTATION = {
2
+ HORIZONTAL: 'horizontal',
3
+ VERTICAL: 'vertical'
4
+ };
5
+
6
+ export const PADDING = {
7
+ SMALL: 'small',
8
+ MEDIUM: 'medium'
9
+ };
10
+
11
+ export const SPACING = {
12
+ SMALL: 'small',
13
+ MEDIUM: 'medium'
14
+ };
@@ -0,0 +1,133 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ import { Animated, View } from 'react-native';
3
+ import { bool, element, object, string } from 'prop-types';
4
+ import React, { useCallback, useRef, useState } from 'react';
5
+
6
+ import { withTheme } from '../../theming';
7
+ import UTBadge from '../UTBadge';
8
+ import UTIcon from '../UTIcon';
9
+ import UTLabel from '../UTLabel';
10
+ import UTButton from '../UTButton';
11
+
12
+ import styleSheet from './styles';
13
+ import { ORIENTATION, PADDING, SPACING } from './constants';
14
+
15
+ const UTDataElement = ({
16
+ action,
17
+ area,
18
+ badge,
19
+ badgeProps,
20
+ children,
21
+ data,
22
+ Data,
23
+ dataProps,
24
+ icon,
25
+ Icon,
26
+ iconProps = {},
27
+ orientation = ORIENTATION.HORIZONTAL,
28
+ padding = PADDING.MEDIUM,
29
+ prefix,
30
+ prefixProps,
31
+ spacing = SPACING.MEDIUM,
32
+ style,
33
+ theme,
34
+ title,
35
+ titleProps
36
+ }) => {
37
+ const styles = styleSheet(theme);
38
+
39
+ const collapsed = useRef(new Animated.Value(1)).current;
40
+ const [childrenHeight, setChildrenHeight] = useState(0);
41
+
42
+ const onLayout = useCallback(
43
+ event => {
44
+ const { height } = event.nativeEvent.layout;
45
+ setChildrenHeight(
46
+ height +
47
+ {
48
+ [PADDING.SMALL]: 8,
49
+ [PADDING.MEDIUM]: 16
50
+ }[padding]
51
+ );
52
+ },
53
+ [padding]
54
+ );
55
+
56
+ const toggleCollapsed = () => {
57
+ Animated.timing(collapsed, {
58
+ toValue: collapsed.__getValue() === 1 ? 0 : 1,
59
+ duration: 300,
60
+ useNativeDriver: false
61
+ }).start();
62
+ };
63
+
64
+ const IconComponent = Icon || (icon ? UTIcon : null);
65
+ const DataComponent = Data || (data ? UTLabel : null);
66
+
67
+ return (
68
+ <View style={[styles.container(area, padding), style]}>
69
+ <View style={styles.content(spacing)}>
70
+ {IconComponent && <IconComponent name={icon} size={24} colorTheme="gray" {...iconProps} />}
71
+ <View style={styles.info(orientation)}>
72
+ {(prefix || title || badge) && (
73
+ <View style={styles.topInfo}>
74
+ {prefix && (
75
+ <UTLabel colorTheme="gray" {...prefixProps}>
76
+ {prefix}
77
+ </UTLabel>
78
+ )}
79
+ {title && (
80
+ <UTLabel colorTheme="gray" {...titleProps}>
81
+ {title}
82
+ </UTLabel>
83
+ )}
84
+ {badge && (
85
+ <UTBadge colorTheme="accent" {...badgeProps}>
86
+ {badge}
87
+ </UTBadge>
88
+ )}
89
+ </View>
90
+ )}
91
+ {DataComponent && <DataComponent {...dataProps}>{data}</DataComponent>}
92
+ </View>
93
+ {action && <UTButton variant="text" {...action} />}
94
+ {children && (
95
+ <Animated.View style={styles.collapseButton(collapsed)}>
96
+ <UTButton Icon="IconChevronDown" variant="text" onPress={toggleCollapsed} />
97
+ </Animated.View>
98
+ )}
99
+ </View>
100
+ {children && (
101
+ <Animated.View style={styles.childrenAnimation(collapsed, childrenHeight)}>
102
+ <View style={styles.childrenContainer} onLayout={onLayout}>
103
+ {children}
104
+ </View>
105
+ </Animated.View>
106
+ )}
107
+ </View>
108
+ );
109
+ };
110
+
111
+ UTDataElement.propTypes = {
112
+ action: object,
113
+ area: bool,
114
+ badge: string,
115
+ badgeProps: object,
116
+ data: string,
117
+ Data: element,
118
+ dataProps: object,
119
+ icon: string,
120
+ Icon: element,
121
+ iconProps: object,
122
+ orientation: string,
123
+ padding: string,
124
+ prefix: string,
125
+ prefixProps: object,
126
+ spacing: string,
127
+ style: object,
128
+ theme: object,
129
+ title: string,
130
+ titleProps: object
131
+ };
132
+
133
+ export default withTheme(UTDataElement);
@@ -0,0 +1,71 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { ORIENTATION, PADDING, SPACING } from './constants';
4
+
5
+ export default StyleSheet.create(({ Palette: { light } }) => ({
6
+ childrenAnimation: (collapsed, childrenHeight) => ({
7
+ height: collapsed.interpolate({
8
+ inputRange: [0, 1],
9
+ outputRange: [0, childrenHeight]
10
+ }),
11
+ overflow: 'hidden',
12
+ position: 'relative'
13
+ }),
14
+ childrenContainer: { position: 'absolute', bottom: 0 },
15
+ collapseButton: collapsed => ({
16
+ borderRadius: collapsed.interpolate({
17
+ inputRange: [0, 0.5, 1],
18
+ outputRange: [0, 100, 0]
19
+ }),
20
+ overflow: 'hidden',
21
+ transform: [
22
+ {
23
+ rotate: collapsed.interpolate({
24
+ inputRange: [0, 1],
25
+ outputRange: ['0deg', '180deg']
26
+ })
27
+ }
28
+ ]
29
+ }),
30
+ container: (area, padding) => ({
31
+ display: 'flex',
32
+ flexDirection: 'column',
33
+ paddingVertical: {
34
+ [PADDING.SMALL]: 8,
35
+ [PADDING.MEDIUM]: 16
36
+ }[padding],
37
+ ...(area
38
+ ? {
39
+ backgroundColor: light['03'],
40
+ paddingLeft: 16,
41
+ paddingRight: 24,
42
+ borderRadius: 8
43
+ }
44
+ : {})
45
+ }),
46
+ content: spacing => ({
47
+ alignItems: 'center',
48
+ display: 'flex',
49
+ flexDirection: 'row',
50
+ gap: {
51
+ [SPACING.SMALL]: 8,
52
+ [SPACING.MEDIUM]: 16
53
+ }[spacing],
54
+ width: '100%'
55
+ }),
56
+ info: orientation => ({
57
+ flexDirection: {
58
+ [ORIENTATION.HORIZONTAL]: 'row',
59
+ [ORIENTATION.VERTICAL]: 'column'
60
+ }[orientation],
61
+ gap: 8,
62
+ justifyContent: 'space-between',
63
+ flex: 1
64
+ }),
65
+ topInfo: {
66
+ alignItems: 'center',
67
+ display: 'flex',
68
+ flexDirection: 'row',
69
+ gap: 8
70
+ }
71
+ }));
@@ -1,14 +1,21 @@
1
1
  export const VARIANTS_SIZES = {
2
- title1: 24,
3
- title2: 22,
4
- title3: 18,
5
- subtitle1: 16,
6
- subtitle2: 14,
7
2
  body: 16,
3
+ number1: 30,
4
+ number2: 24,
5
+ number3: 22,
6
+ number4: 18,
7
+ number5: 16,
8
+ number6: 14,
9
+ number7: 13,
8
10
  small: 14,
9
- xsmall: 11,
11
+ subtitle1: 16,
12
+ subtitle2: 14,
13
+ td: 16,
10
14
  th: 16,
11
- td: 16
15
+ title1: 24,
16
+ title2: 22,
17
+ title3: 18,
18
+ xsmall: 11
12
19
  };
13
20
 
14
21
  export const LINE_HEIGHTS = {
@@ -64,5 +64,8 @@ export default StyleSheet.create({
64
64
  justifyContent: 'center',
65
65
  padding: 12,
66
66
  width: '100%'
67
- })
67
+ }),
68
+ label: {
69
+ textAlign: 'center'
70
+ }
68
71
  });
@@ -8,7 +8,7 @@ import { useTheme } from '../../../../../../../../theming';
8
8
 
9
9
  import ownStyles from './styles';
10
10
 
11
- const ActionButton = ({ colorTheme, disabled, hidden, label, onPress, style, variant }) => {
11
+ const ActionButton = ({ colorTheme, disabled, hidden, label, onPress, style, variant, icon }) => {
12
12
  const theme = useTheme();
13
13
  const themedStyles = merge({}, ownStyles, theme?.UTWorkflowContainer?.actionButton, style);
14
14
 
@@ -21,6 +21,7 @@ const ActionButton = ({ colorTheme, disabled, hidden, label, onPress, style, var
21
21
  size="large"
22
22
  style={{ root: themedStyles.buttonContainer, childrenContainer: themedStyles.buttonContent }}
23
23
  variant={variant}
24
+ Icon={icon}
24
25
  >
25
26
  {label}
26
27
  </UTButton>
@@ -32,6 +33,7 @@ ActionButton.propTypes = {
32
33
  colorTheme: string,
33
34
  disabled: bool,
34
35
  hidden: bool,
36
+ icon: string,
35
37
  label: string,
36
38
  onPress: func,
37
39
  variant: string
package/lib/index.js CHANGED
@@ -45,6 +45,8 @@ export { default as UTButtonGroup } from './components/UTButtonGroup';
45
45
  export { default as UTCBUInput } from './components/UTCBUInput';
46
46
  export { default as UTCheckBox } from './components/UTCheckBox';
47
47
  export { default as UTCheckList } from './components/UTCheckList';
48
+ export { default as UTDataCategory } from './components/UTDataCategory';
49
+ export { default as UTDataElement } from './components/UTDataElement';
48
50
  export { default as UTDetailDrawer } from './components/UTDetailDrawer';
49
51
  export { default as UTIcon } from './components/UTIcon';
50
52
  export { default as UTImage } from './components/UTImage';
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.37.0",
5
+ "version": "1.38.0",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [