@widergy/mobile-ui 1.6.0 → 1.8.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/lib/components/MultipleFilePicker/components/Input/README.md +77 -0
  3. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/constants.js +2 -0
  4. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/index.js +27 -0
  5. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/propTypes.js +8 -0
  6. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/styles.js +15 -0
  7. package/lib/components/MultipleFilePicker/components/Input/components/Title/index.js +78 -0
  8. package/lib/components/MultipleFilePicker/components/Input/components/Title/propTypes.js +14 -0
  9. package/lib/components/MultipleFilePicker/components/Input/components/Title/styles.js +42 -0
  10. package/lib/components/MultipleFilePicker/components/Input/components/Underline/index.js +80 -0
  11. package/lib/components/MultipleFilePicker/components/Input/components/Underline/styles.js +39 -0
  12. package/lib/components/MultipleFilePicker/components/Input/constants.js +2 -0
  13. package/lib/components/MultipleFilePicker/components/Input/index.js +299 -0
  14. package/lib/components/MultipleFilePicker/components/Input/propTypes.js +43 -0
  15. package/lib/components/MultipleFilePicker/components/Input/styles.js +47 -0
  16. package/lib/components/MultipleFilePicker/components/Picker/index.js +95 -0
  17. package/lib/components/MultipleFilePicker/components/Picker/styles.js +47 -0
  18. package/lib/components/MultipleFilePicker/components/UploadedFiles/index.js +140 -0
  19. package/lib/components/MultipleFilePicker/components/UploadedFiles/styles.js +65 -0
  20. package/lib/components/MultipleFilePicker/components/UploadedFiles/utils.js +6 -0
  21. package/lib/components/MultipleFilePicker/constants.js +18 -0
  22. package/lib/components/MultipleFilePicker/index.js +162 -0
  23. package/lib/components/MultipleFilePicker/propTypes.js +17 -0
  24. package/lib/components/MultipleFilePicker/utils.js +41 -0
  25. package/lib/components/UTTracker/README.md +24 -0
  26. package/lib/components/UTTracker/components/Connectors/index.js +26 -0
  27. package/lib/components/UTTracker/components/Connectors/styles.js +20 -0
  28. package/lib/components/UTTracker/components/Step/index.js +114 -0
  29. package/lib/components/UTTracker/components/Step/styles.js +80 -0
  30. package/lib/components/UTTracker/components/SubStep/index.js +28 -0
  31. package/lib/components/UTTracker/components/SubStep/styles.js +10 -0
  32. package/lib/components/UTTracker/constants.js +4 -0
  33. package/lib/components/UTTracker/index.js +120 -0
  34. package/lib/components/UTTracker/propTypes.js +19 -0
  35. package/lib/components/UTTracker/styles.js +57 -0
  36. package/lib/index.js +2 -0
  37. package/package.json +3 -2
@@ -0,0 +1,65 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { portraitHorizontalScale, portraitVerticalScale } from '../../../../utils/portraitScalingUtils';
4
+
5
+ export default StyleSheet.create({
6
+ container: {
7
+ flexDirection: 'row'
8
+ },
9
+ containerInput: {
10
+ height: '100%',
11
+ width: '100%'
12
+ },
13
+ containerStyle: {
14
+ flex: 1,
15
+ shadowColor: '#E4E6EA',
16
+ elevation: 4
17
+ },
18
+ containerButtonPadding: {
19
+ padding: portraitHorizontalScale(65)
20
+ },
21
+ containerPadding: {
22
+ padding: portraitHorizontalScale(18)
23
+ },
24
+ fieldInput: {
25
+ borderRadius: 5,
26
+ borderStyle: 'dashed',
27
+ borderWidth: 1,
28
+ flex: 1,
29
+ height: 'auto',
30
+ paddingBottom: portraitVerticalScale(24),
31
+ paddingTop: portraitVerticalScale(16),
32
+ width: '100%',
33
+ marginVertical: 10
34
+ },
35
+ helpText: {
36
+ textAlign: 'center',
37
+ marginBottom: 10
38
+ },
39
+ pickerText: {
40
+ textAlign: 'center'
41
+ },
42
+ textStyles: {
43
+ marginLeft: 5,
44
+ marginTop: 16
45
+ },
46
+ textButtonStyles: {
47
+ flex: 1,
48
+ padding: 0,
49
+ textAlignVertical: 'center',
50
+ margin: 15
51
+ },
52
+ touchable: {
53
+ borderRadius: 4,
54
+ paddingHorizontal: portraitHorizontalScale(12),
55
+ height: 80,
56
+ width: '100%'
57
+ },
58
+ uploadTouchable: {
59
+ borderRadius: 4,
60
+ marginHorizontal: 16,
61
+ marginVertical: 10,
62
+ height: 38,
63
+ width: '90%'
64
+ }
65
+ });
@@ -0,0 +1,6 @@
1
+ export const bytesFormater = bytes => {
2
+ const lista = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
3
+ if (bytes === 0) return '0 Byte';
4
+ const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
5
+ return `${Math.round(bytes / 1024 ** i, 2)} ${lista[i]}`;
6
+ };
@@ -0,0 +1,18 @@
1
+ // eslint-disable-next-line import/no-unresolved
2
+ import DocumentPicker from 'react-native-document-picker';
3
+
4
+ import { MEGABYTE } from '../../utils/fileUtils.js';
5
+
6
+ export const FILE_UPLOAD_ICON = 'file-upload';
7
+
8
+ export const UPLOAD_ICON = 'upload';
9
+
10
+ export const CHECK_ICON = 'check';
11
+
12
+ export const TRASH_ICON = 'trash-2';
13
+
14
+ export const TYPE_ICON = 'feather';
15
+
16
+ export const DEFAULT_ALLOWED_TYPES = [DocumentPicker.types.allFiles];
17
+
18
+ export const DEFAULT_MAX_SIZE = 10 * MEGABYTE;
@@ -0,0 +1,162 @@
1
+ import React, { Component } from 'react';
2
+ import { View } from 'react-native';
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import DocumentPicker from 'react-native-document-picker';
5
+ import { isEmpty } from '@widergy/web-utils/lib/array';
6
+
7
+ import { retrieveFile, isImageByUri, blobToFile } from '../../utils/fileUtils.js';
8
+
9
+ import Picker from './components/Picker';
10
+ import UploadedFiles from './components/UploadedFiles';
11
+ import { UPLOAD_ICON, DEFAULT_MAX_SIZE } from './constants';
12
+ import filePickerPropTypes from './propTypes';
13
+ import { onlyPDFAllowed, pdfAspectRatioValidation } from './utils';
14
+
15
+ class MultipleFilePicker extends Component {
16
+ constructor(props) {
17
+ super(props);
18
+ this.state = {
19
+ uploadedFiles: []
20
+ };
21
+ }
22
+
23
+ handleShowPicker = async () => {
24
+ const {
25
+ allowedTypes,
26
+ onMaxSizeError,
27
+ onError,
28
+ onChange,
29
+ maxFileByteSize,
30
+ maxFiles,
31
+ minFiles,
32
+ avoidRetrieveFile,
33
+ fileTypeError,
34
+ allowedPDFUploadSizes,
35
+ pdfFormatError
36
+ } = this.props;
37
+ try {
38
+ const documents = await DocumentPicker.pick({
39
+ allowMultiSelection: true,
40
+ type: allowedTypes && !onlyPDFAllowed(allowedTypes) ? allowedTypes : DocumentPicker.types.allFiles
41
+ });
42
+ const { uploadedFiles } = this.state;
43
+
44
+ if (uploadedFiles.length + documents.length > maxFiles) {
45
+ throw new Error(fileTypeError || 'La cantidad de archivos supera al máximo permitido');
46
+ }
47
+ if (uploadedFiles.length + documents.length < minFiles) {
48
+ throw new Error(fileTypeError || 'La cantidad de archivos es menor al mínimo permitido');
49
+ }
50
+ documents.map(async document => {
51
+ const isPDF = document.type.includes('pdf');
52
+ const isImage = document.type.includes('image');
53
+ if (onlyPDFAllowed(allowedTypes) && !isPDF) {
54
+ throw new Error(fileTypeError || 'El tipo de archivo debe ser PDF.');
55
+ }
56
+ if (allowedTypes && !isImage && !isImageByUri(document.uri) && !isPDF) {
57
+ throw new Error(fileTypeError || 'Tipo de archivo inválido.');
58
+ }
59
+ if (maxFileByteSize && document.size > maxFileByteSize) {
60
+ onMaxSizeError(document.size, maxFileByteSize);
61
+ return;
62
+ }
63
+
64
+ const file = !avoidRetrieveFile && (await retrieveFile(document.uri, document.type));
65
+
66
+ if (file && isPDF && !isEmpty(allowedPDFUploadSizes)) {
67
+ const isWrongFormat = await pdfAspectRatioValidation(file, allowedPDFUploadSizes);
68
+ if (isWrongFormat) {
69
+ throw new Error(
70
+ pdfFormatError ||
71
+ `El formato de archivo es inválido. (Válidos: ${allowedPDFUploadSizes
72
+ ?.map(aspectRatio => aspectRatio.name)
73
+ .join(' - ')})`
74
+ );
75
+ }
76
+ }
77
+
78
+ if (onChange) {
79
+ onChange(avoidRetrieveFile ? { document } : { file: blobToFile(file, document.type) });
80
+ }
81
+ this.setState(prevState => ({
82
+ uploadedFiles: [...prevState.uploadedFiles, { name: document.name, size: document.size }]
83
+ }));
84
+ });
85
+ } catch (err) {
86
+ if (!DocumentPicker.isCancel(err)) {
87
+ onError(err.message);
88
+ }
89
+ }
90
+ };
91
+
92
+ handleDeleteFile = index => {
93
+ const { onChange } = this.props;
94
+ if (onChange) {
95
+ onChange(null);
96
+ }
97
+ this.setState(prevState => ({
98
+ uploadedFiles: prevState.uploadedFiles.filter((a, i) => i !== index)
99
+ }));
100
+ };
101
+
102
+ render() {
103
+ const {
104
+ error,
105
+ title,
106
+ filePlaceholder,
107
+ style,
108
+ withMarkdownTitle,
109
+ markdownStyles,
110
+ disabled,
111
+ helpText,
112
+ pickerText,
113
+ UploadIcon
114
+ } = this.props;
115
+ const { uploadedFiles } = this.state;
116
+
117
+ return uploadedFiles.length !== 0 ? (
118
+ <View style={style}>
119
+ <UploadedFiles
120
+ icon={UPLOAD_ICON}
121
+ error={error}
122
+ onAdd={this.handleShowPicker}
123
+ onDelete={this.handleDeleteFile}
124
+ uploadedFiles={uploadedFiles}
125
+ filePlaceholder={filePlaceholder}
126
+ title={title}
127
+ withMarkdownTitle={withMarkdownTitle}
128
+ markdownStyles={markdownStyles}
129
+ disabled={disabled}
130
+ pickerText={pickerText}
131
+ helpText={helpText}
132
+ />
133
+ </View>
134
+ ) : (
135
+ <View style={style}>
136
+ <Picker
137
+ icon={UPLOAD_ICON}
138
+ error={error}
139
+ onAdd={this.handleShowPicker}
140
+ onDelete={this.handleDeleteFile}
141
+ uploadedFiles={uploadedFiles}
142
+ filePlaceholder={filePlaceholder}
143
+ title={title}
144
+ withMarkdownTitle={withMarkdownTitle}
145
+ markdownStyles={markdownStyles}
146
+ disabled={disabled}
147
+ pickerText={pickerText}
148
+ helpText={helpText}
149
+ UploadIcon={UploadIcon}
150
+ />
151
+ </View>
152
+ );
153
+ }
154
+ }
155
+
156
+ MultipleFilePicker.defaultProps = {
157
+ maxFileByteSize: DEFAULT_MAX_SIZE
158
+ };
159
+
160
+ MultipleFilePicker.propTypes = filePickerPropTypes;
161
+
162
+ export default MultipleFilePicker;
@@ -0,0 +1,17 @@
1
+ import { oneOfType, string, bool, func, number, arrayOf, shape } from 'prop-types';
2
+
3
+ export default {
4
+ error: oneOfType([string, bool]),
5
+ onChange: func,
6
+ allowedTypes: arrayOf(string),
7
+ filePlaceholder: string,
8
+ title: string,
9
+ onMaxSizeError: func,
10
+ maxFileByteSize: number,
11
+ onError: func,
12
+ fileTypeError: string,
13
+ allowedPDFUploadSizes: arrayOf(
14
+ shape({ name: string, heightInPt: number, widthInPt: number, tolerance: number })
15
+ ),
16
+ disabled: bool
17
+ };
@@ -0,0 +1,41 @@
1
+ import { PDFDocument } from 'pdf-lib';
2
+
3
+ export const onlyPDFAllowed = allowedTypes => allowedTypes.length === 1 && allowedTypes[0].includes('pdf');
4
+
5
+ const lengthMatches = (length1, length2, toleranceInPercentage) => {
6
+ const delta = length1 * (toleranceInPercentage / 100);
7
+ return Math.abs(length1 - length2) < delta;
8
+ };
9
+
10
+ const pageMatches = (pageSize, allowedPDFUploadSizes) =>
11
+ allowedPDFUploadSizes.some(
12
+ size =>
13
+ (lengthMatches(size.heightInPt, pageSize.height, size.toleranceInPercentage) &&
14
+ lengthMatches(size.widthInPt, pageSize.width, size.toleranceInPercentage)) ||
15
+ (lengthMatches(size.heightInPt, pageSize.width, size.toleranceInPercentage) &&
16
+ lengthMatches(size.widthInPt, pageSize.height, size.toleranceInPercentage))
17
+ );
18
+
19
+ const blobToBase64 = blob =>
20
+ new Promise((resolve, reject) => {
21
+ const reader = new FileReader();
22
+ reader.onload = function () {
23
+ const result = reader.result.replace(/^data:.+;base64,/, '');
24
+ resolve(result);
25
+ };
26
+ reader.onerror = function () {
27
+ reject(new Error('No es posible leer el archivo.'));
28
+ };
29
+ reader.readAsDataURL(blob);
30
+ });
31
+
32
+ export const pdfAspectRatioValidation = async (file, allowedPDFUploadSizes) => {
33
+ const base64 = await blobToBase64(file);
34
+ const pdf = await PDFDocument.load(base64);
35
+ const pages = pdf.getPages();
36
+
37
+ return pages.some(page => {
38
+ const { width, height } = page.getSize();
39
+ return !pageMatches({ width, height }, allowedPDFUploadSizes);
40
+ });
41
+ };
@@ -0,0 +1,24 @@
1
+ # UTTracker
2
+
3
+ ### Description
4
+
5
+ This component displays a vertical stepper intended to track progress
6
+
7
+ ## Props
8
+
9
+ | Name | Type | Default | Description |
10
+ | ----------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | title | string | | Displays the title above the tracker. |
12
+ | mode | card \| flat | card | Defines whether the component should display as a card or as the bare components without any background. |
13
+ | variant | standard \| error | standard | Defines the color scheme of the tracker steps and the icon on the active step. |
14
+ | steps | stepsType | | Displays a step with a rounded icon on the left for each object received. |
15
+ | currentStep | number | | Defines which step will be active, previous ones will be marked as completed while following ones will not. Use 1 for the first step |
16
+ | detailsTab | detailsType | | Defines whether the detailsTab is enabled or not, if it is, it will show the subSteps of each step. The title property shows a message along the tab (card mode only) |
17
+
18
+ ### Custom Types
19
+
20
+ | Type | Shape |
21
+ | ------------ | ------------------------------------------------------------------------------ |
22
+ | stepsType | `{ id: number, title: string, subtitle: string, subSteps: [...subStepsType] }` |
23
+ | subStepsType | `{ id: number, title: string, subtitle: string }` |
24
+ | detailsType | `{ enabled: bool, title: string }` |
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import { number } from 'prop-types';
4
+ import merge from 'lodash/merge';
5
+ import { ViewPropTypes } from 'deprecated-react-native-prop-types';
6
+
7
+ import ownStyles from './styles';
8
+
9
+ const Connectors = ({ firstStepPosition, lastStepPosition, stepperHeight, style }) => {
10
+ const themedStyles = merge({}, ownStyles, style);
11
+
12
+ return (
13
+ <View style={themedStyles.wrapper(firstStepPosition, lastStepPosition, stepperHeight)}>
14
+ <View style={themedStyles.connectors} />
15
+ </View>
16
+ );
17
+ };
18
+
19
+ Connectors.propTypes = {
20
+ firstStepPosition: number,
21
+ lastStepPosition: number,
22
+ stepperHeight: number,
23
+ style: ViewPropTypes.style
24
+ };
25
+
26
+ export default Connectors;
@@ -0,0 +1,20 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { OVAL_SIZE } from '../../styles';
4
+
5
+ export default StyleSheet.create({
6
+ connectors: {
7
+ borderColor: 'gray',
8
+ borderLeftWidth: 2,
9
+ borderStyle: 'dashed',
10
+ flexGrow: 1
11
+ },
12
+ wrapper: (firstStepPosition, lastStepHeight, stepperHeight) => ({
13
+ height: '100%',
14
+ paddingBottom: stepperHeight - lastStepHeight,
15
+ paddingLeft: OVAL_SIZE / 2 - 1,
16
+ paddingTop: OVAL_SIZE + 4 + firstStepPosition,
17
+ position: 'absolute',
18
+ width: 2
19
+ })
20
+ });
@@ -0,0 +1,114 @@
1
+ import React, { useState } from 'react';
2
+ import { View } from 'react-native';
3
+ import { bool, func } from 'prop-types';
4
+ import merge from 'lodash/merge';
5
+
6
+ import Label from '../../../Label';
7
+ import { StepPropTypes, VariantPropTypes } from '../../propTypes';
8
+ import Icon from '../../../Icon';
9
+ import { ERROR } from '../../constants';
10
+
11
+ import ownStyles, { ownVariantStyles } from './styles';
12
+
13
+ const ERROR_ICON_SIZE = 16;
14
+
15
+ const Step = ({
16
+ first,
17
+ isActive,
18
+ isCompleted,
19
+ last,
20
+ setFirstStepPosition,
21
+ setLastStepPosition,
22
+ step,
23
+ style = {},
24
+ variant
25
+ }) => {
26
+ const stepCompleted = isCompleted(step.id);
27
+ const stepActive = isActive(step.id);
28
+
29
+ const themedStyles = merge({}, ownStyles, ownVariantStyles[variant], style[variant]);
30
+
31
+ const [stepIconOffset, setStepIconOffset] = useState(0);
32
+
33
+ return (
34
+ <View
35
+ onLayout={e => {
36
+ if (first) setFirstStepPosition(e.nativeEvent.layout.y + stepIconOffset);
37
+ if (last) setLastStepPosition(e.nativeEvent.layout.y + stepIconOffset);
38
+ }}
39
+ style={[
40
+ themedStyles.outerContainer,
41
+ stepCompleted && themedStyles.completedOuterContainer,
42
+ stepActive && themedStyles.activeOuterContainer,
43
+ !first && ownStyles.stepMargin
44
+ ]}
45
+ >
46
+ <View
47
+ onLayout={e => (first || last) && setStepIconOffset(e.nativeEvent.layout.y)}
48
+ style={[
49
+ themedStyles.container,
50
+ stepCompleted && themedStyles.completedContainer,
51
+ stepActive && themedStyles.activeContainer
52
+ ]}
53
+ >
54
+ <View
55
+ style={[
56
+ themedStyles.innerContainer,
57
+ stepCompleted && themedStyles.completedInnerContainer,
58
+ stepActive && themedStyles.activeInnerContainer
59
+ ]}
60
+ >
61
+ {stepActive && variant === ERROR && (
62
+ <Icon
63
+ color="white"
64
+ height={ERROR_ICON_SIZE}
65
+ name="close"
66
+ size={ERROR_ICON_SIZE}
67
+ style={themedStyles.icon}
68
+ type="antdesign"
69
+ width={ERROR_ICON_SIZE}
70
+ />
71
+ )}
72
+ </View>
73
+ </View>
74
+ <View style={themedStyles.textContainer}>
75
+ {step.title && (
76
+ <Label
77
+ color={
78
+ stepCompleted
79
+ ? themedStyles.completedTitleColor
80
+ : stepActive
81
+ ? themedStyles.activeTitleColor
82
+ : themedStyles.titleColor
83
+ }
84
+ >
85
+ {step.title}
86
+ </Label>
87
+ )}
88
+ {step.subtitle && (
89
+ <Label color={themedStyles.subtitleColor} style={themedStyles.subtitle}>
90
+ {step.subtitle}
91
+ </Label>
92
+ )}
93
+ {step.description && (
94
+ <Label color={themedStyles.descriptionColor} style={themedStyles.description}>
95
+ {step.description}
96
+ </Label>
97
+ )}
98
+ </View>
99
+ </View>
100
+ );
101
+ };
102
+
103
+ Step.propTypes = {
104
+ first: bool,
105
+ isActive: func,
106
+ isCompleted: func,
107
+ last: bool,
108
+ setFirstStepPosition: func,
109
+ setLastStepPosition: func,
110
+ step: StepPropTypes,
111
+ variant: VariantPropTypes
112
+ };
113
+
114
+ export default Step;
@@ -0,0 +1,80 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { OVAL_SIZE } from '../../styles';
4
+ import { ERROR, STANDARD } from '../../constants';
5
+
6
+ export const ownVariantStyles = {
7
+ [ERROR]: {
8
+ activeContainer: {
9
+ backgroundColor: 'red',
10
+ borderColor: 'red'
11
+ },
12
+ activeInnerContainer: {
13
+ backgroundColor: 'red'
14
+ },
15
+ activeTitleColor: 'red',
16
+ completedContainer: {
17
+ borderColor: '#F38595'
18
+ },
19
+ completedInnerContainer: {
20
+ backgroundColor: '#F38595'
21
+ },
22
+ completedTitleColor: '#F38595'
23
+ },
24
+ [STANDARD]: {
25
+ activeContainer: {
26
+ borderColor: 'blue'
27
+ },
28
+ activeInnerContainer: {
29
+ backgroundColor: 'blue'
30
+ },
31
+ activeTitleColor: 'blue',
32
+ completedContainer: {
33
+ borderColor: '#93ACFF'
34
+ },
35
+ completedInnerContainer: {
36
+ backgroundColor: '#93ACFF'
37
+ },
38
+ completedTitleColor: '#93ACFF'
39
+ }
40
+ };
41
+
42
+ export default StyleSheet.create({
43
+ container: {
44
+ alignItems: 'center',
45
+ backgroundColor: 'white',
46
+ borderColor: 'gray',
47
+ borderRadius: OVAL_SIZE / 2,
48
+ borderWidth: OVAL_SIZE / 10,
49
+ height: OVAL_SIZE,
50
+ justifyContent: 'center',
51
+ marginRight: 16,
52
+ width: OVAL_SIZE
53
+ },
54
+ description: {
55
+ marginTop: 4
56
+ },
57
+ descriptionColor: 'gray',
58
+ icon: {
59
+ position: 'absolute',
60
+ right: -3,
61
+ top: -3
62
+ },
63
+ innerContainer: {
64
+ backgroundColor: 'white',
65
+ borderRadius: OVAL_SIZE / 4,
66
+ height: OVAL_SIZE / 2,
67
+ width: OVAL_SIZE / 2
68
+ },
69
+ outerContainer: {
70
+ alignItems: 'center',
71
+ flexDirection: 'row'
72
+ },
73
+ stepMargin: { marginTop: 24 },
74
+ subtitle: {
75
+ marginTop: 4
76
+ },
77
+ textContainer: {
78
+ width: '90%'
79
+ }
80
+ });
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import { string } from 'prop-types';
4
+ import merge from 'lodash/merge';
5
+ import { ViewPropTypes } from 'deprecated-react-native-prop-types';
6
+
7
+ import Label from '../../../Label';
8
+
9
+ import ownStyles from './styles';
10
+
11
+ const SubStep = ({ style, subtitle, title }) => {
12
+ const themedStyles = merge({}, ownStyles, style);
13
+
14
+ return (
15
+ <View style={themedStyles.container}>
16
+ <Label color={themedStyles.titleColor}>{title}</Label>
17
+ <Label color={themedStyles.subtitleColor}>{subtitle}</Label>
18
+ </View>
19
+ );
20
+ };
21
+
22
+ SubStep.propTypes = {
23
+ style: ViewPropTypes.style,
24
+ subtitle: string,
25
+ title: string
26
+ };
27
+
28
+ export default SubStep;
@@ -0,0 +1,10 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ container: {
5
+ marginLeft: 36,
6
+ marginTop: 8
7
+ },
8
+ subtitleColor: 'lightgray',
9
+ titleColor: 'gray'
10
+ });
@@ -0,0 +1,4 @@
1
+ export const CARD = 'card';
2
+ export const FLAT = 'flat';
3
+ export const STANDARD = 'standard';
4
+ export const ERROR = 'error';