@momo-kits/step 0.0.60-rc.6 → 0.0.61-alpha.10

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.
@@ -1,434 +1,252 @@
1
- import { Colors, IconSource, Image, Text } from '@momo-kits/core';
1
+ import { Colors, IconSource, Image, Spacing, Text } from '@momo-kits/core-v2';
2
2
  import PropTypes from 'prop-types';
3
- import React, { Component } from 'react';
4
- import { Dimensions, StyleSheet, View } from 'react-native';
5
- import { IS_VALID_URL } from './Step.constants';
3
+ import React from 'react';
4
+ import { StyleSheet, View } from 'react-native';
5
+
6
+ const HorizontalStep = (props) => {
7
+ const {
8
+ steps = {},
9
+ currentStep,
10
+ type,
11
+ activeCircleColor,
12
+ inactiveCircleColor,
13
+ checkedCircleColor,
14
+ activeBorderColor,
15
+ inactiveBorderColor,
16
+ activeLineColor,
17
+ inactiveLineColor,
18
+ style,
19
+ size = 'default',
20
+ checkIcon,
21
+ errorIcon,
22
+ } = props;
23
+
24
+ let CIRCLE_SIZE = 24;
25
+ let CIRCLE_TEXT_SIZE = 12;
26
+ let ICON_SIZE = 16;
27
+ let TITLE_SIZE = { size: 14, lineHeight: 20 };
28
+ let SUBTITLE_SIZE = { size: 10, lineHeight: 14 };
29
+ let CONTENT_SIZE = { size: 12, lineHeight: 16 };
30
+ const ICON_URL = checkIcon || IconSource.ic_check_24;
31
+ const ERROR_ICON_URL = errorIcon || IconSource.ic_close_x_24;
32
+ if (size === 'small') {
33
+ CIRCLE_SIZE = 16;
34
+ CIRCLE_TEXT_SIZE = 8;
35
+ ICON_SIZE = 12;
36
+ TITLE_SIZE = { size: 12, lineHeight: 16 };
37
+ SUBTITLE_SIZE = { size: 10, lineHeight: 14 };
38
+ CONTENT_SIZE = { size: 10, lineHeight: 14 };
39
+ }
6
40
 
7
- const CIRCLE_SIZE = 24;
8
- const SCREEN_WIDTH = Dimensions.get('window').width;
41
+ const renderCircle = (error, index) => {
42
+ let circleColor = inactiveCircleColor;
43
+ let borderColor = inactiveBorderColor;
9
44
 
10
- const styles = StyleSheet.create({
11
- circle: {
12
- width: CIRCLE_SIZE,
13
- height: CIRCLE_SIZE,
14
- borderRadius: CIRCLE_SIZE / 2,
15
- borderWidth: 2,
16
- padding: 4,
17
- },
18
- iconImage: {
19
- width: 16,
20
- height: 16,
21
- position: 'absolute',
22
- top: 2,
23
- left: 2,
24
- },
25
- titleDefault: {
26
- fontSize: 14,
27
- color: Colors.black_12,
28
- fontWeight: 'normal',
29
- },
30
- titleActive: {
31
- fontSize: 14,
32
- color: Colors.black_17,
33
- fontWeight: 'bold',
34
- },
35
- description: {
36
- fontSize: 12,
37
- color: Colors.black_12,
38
- marginBottom: 16,
39
- paddingTop: 4,
40
- paddingLeft: 11,
41
- },
42
- date: {
43
- fontSize: 10,
44
- color: Colors.black_12,
45
- },
46
- number: {
47
- fontSize: 12,
48
- color: 'white',
49
- textAlign: 'center',
50
- lineHeight: 13,
51
- },
52
- lineHorizontal: {
53
- height: 2,
54
- width: '100%',
55
- },
56
- minHeight: {
57
- minHeight: 12,
58
- marginBottom: 4,
59
- },
60
- });
61
- export default class HorizontalStep extends Component {
62
- constructor(props) {
63
- super(props);
64
- this.state = {
65
- width: 0,
66
- height: 0,
67
- };
68
- }
45
+ if (index < currentStep) circleColor = checkedCircleColor;
46
+ else if (index === currentStep) circleColor = activeCircleColor;
69
47
 
70
- onLayout = (e) => {
71
- this.setState({
72
- width: e.nativeEvent.layout.width,
73
- height: e.nativeEvent.layout.height,
74
- });
75
- };
48
+ if (index <= currentStep) borderColor = activeBorderColor;
76
49
 
77
- _renderCircleImage = ({
78
- icon = '',
79
- circleColor = '',
80
- circleBorderColor = '',
81
- }) => {
50
+ if (error) {
51
+ circleColor = Colors.red_03;
52
+ borderColor = Colors.red_08;
53
+ }
82
54
  return (
83
- <View>
84
- <View
85
- style={[
86
- styles.circle,
87
- {
88
- backgroundColor: circleColor,
89
- borderColor: circleBorderColor,
90
- },
91
- ]}>
92
- <Image
93
- source={icon}
94
- style={[styles.iconImage, { tintColor: '#ffffff' }]}
95
- />
96
- </View>
55
+ <View
56
+ style={[
57
+ styles.circle,
58
+ {
59
+ width: CIRCLE_SIZE,
60
+ height: CIRCLE_SIZE,
61
+ borderRadius: CIRCLE_SIZE / 2,
62
+ borderColor: borderColor,
63
+ backgroundColor: circleColor,
64
+ },
65
+ ]}>
66
+ {renderCircleContent(error, index)}
97
67
  </View>
98
68
  );
99
69
  };
100
70
 
101
- _renderCircleText = ({
102
- circleColor = '',
103
- circleBorderColor = '',
104
- index = 0,
105
- }) => {
106
- return (
107
- <View>
108
- <View
71
+ const renderCircleContent = (error, index) => {
72
+ const icon = error ? ERROR_ICON_URL : ICON_URL;
73
+ if (type === 'check') {
74
+ return (
75
+ <Image
76
+ source={icon}
109
77
  style={[
110
- styles.circle,
111
- {
112
- backgroundColor: circleColor,
113
- borderColor: circleBorderColor,
114
- },
115
- ]}>
116
- <Text style={styles.number}>{index + 1}</Text>
117
- </View>
118
- </View>
119
- );
120
- };
121
-
122
- _renderDateOrValue = ({
123
- date = '',
124
- isActiveState = false,
125
- circleChecked = false,
126
- minHeight = 0,
127
- dateStyle = {},
128
- index = 0,
129
- }) => {
130
- // Init states in render function
131
- let resultComponent = <></>;
132
- if (!date) {
133
- return resultComponent;
134
- }
135
- if (isActiveState || circleChecked) {
136
- resultComponent = (
78
+ styles.icon,
79
+ { width: ICON_SIZE, height: ICON_SIZE },
80
+ ]}
81
+ />
82
+ );
83
+ } else if (type === 'combine') {
84
+ return index < currentStep ? (
85
+ <Image
86
+ source={icon}
87
+ style={[
88
+ styles.icon,
89
+ { width: ICON_SIZE, height: ICON_SIZE },
90
+ ]}
91
+ />
92
+ ) : (
137
93
  <Text
138
94
  style={[
139
- styles.date,
140
- dateStyle,
141
- { minHeight: 12, marginBottom: 4 },
95
+ styles.circleText,
96
+ {
97
+ fontSize: CIRCLE_TEXT_SIZE,
98
+ lineHeight: CIRCLE_TEXT_SIZE + 2,
99
+ },
142
100
  ]}>
143
- {date[index]}
101
+ {index + 1}
144
102
  </Text>
145
103
  );
146
- } else {
147
- resultComponent = <View style={minHeight}></View>;
148
104
  }
149
- return resultComponent;
150
- };
151
-
152
- _renderCircle = ({
153
- circleColor = '',
154
- circleBorderColor = '',
155
- isActiveState = false,
156
- circleUnchecked = false,
157
- iconActive = '',
158
- iconUnchecked = '',
159
- icon = {},
160
- index = 0,
161
- }) => {
162
- let resultComponent = <></>;
163
- if (!isActiveState) {
164
- if (circleUnchecked) {
165
- if (IS_VALID_URL.test(iconUnchecked)) {
166
- resultComponent = this._renderCircleImage({
167
- icon,
168
- circleColor,
169
- circleBorderColor,
170
- });
171
- } else {
172
- resultComponent = this._renderCircleText({
173
- circleColor,
174
- circleBorderColor,
175
- index,
176
- });
177
- }
178
- } else {
179
- resultComponent = this._renderCircleImage({
180
- icon,
181
- circleColor,
182
- circleBorderColor,
183
- });
184
- }
185
- } else {
186
- // This is active case
187
- // If icon diff "" & regex http or https url so will render image component
188
- if (IS_VALID_URL.test(iconActive)) {
189
- resultComponent = this._renderCircleImage({
190
- icon,
191
- circleColor,
192
- circleBorderColor,
193
- });
194
- } else {
195
- // Otherwise render index number in text component
196
- resultComponent = resultComponent = this._renderCircleText({
197
- circleColor,
198
- circleBorderColor,
199
- index,
200
- });
201
- }
202
- }
203
- return resultComponent;
204
- };
205
-
206
- _renderTitle = ({ textFontStyle = {}, titleStyle = {}, value = {} }) => {
207
- let resultComponent = (
208
- <View>
209
- <Text.Caption
210
- style={[{ marginTop: 4 }, textFontStyle, titleStyle]}>
211
- {value}
212
- </Text.Caption>
213
- </View>
105
+ return (
106
+ <Text
107
+ style={[
108
+ styles.circleText,
109
+ {
110
+ fontSize: CIRCLE_TEXT_SIZE,
111
+ lineHeight: CIRCLE_TEXT_SIZE + 2,
112
+ },
113
+ ]}>
114
+ {index + 1}
115
+ </Text>
214
116
  );
215
- return resultComponent;
216
117
  };
217
118
 
218
- _renderDescription = ({ items = {}, descriptionStyle = {}, index = 0 }) => {
219
- let resultComponent = <></>;
220
-
221
- if (items) {
222
- resultComponent = (
223
- <View>
224
- <Text style={[{ fontSize: 10 }, descriptionStyle]}>
225
- {items[index]}
226
- </Text>
227
- </View>
228
- );
229
- }
230
- return resultComponent;
231
- };
119
+ const renderLine = (index) => {
120
+ let lineColor =
121
+ index < currentStep ? activeLineColor : inactiveLineColor;
232
122
 
233
- _renderLine = ({
234
- titles = {},
235
- index = 0,
236
- lineRight = 0,
237
- lineWidth = 0,
238
- lineActive = '',
239
- date,
240
- }) => {
241
- let resultComponent = <></>;
123
+ if (index === -1 || index === steps.length - 1)
124
+ lineColor = 'transparent';
242
125
 
243
- if (titles?.length - 1 !== index) {
244
- resultComponent = (
245
- <View
246
- style={{
247
- position: 'absolute',
248
- right: lineRight,
249
- width: lineWidth,
250
- zIndex: -1,
251
- }}>
252
- <View
253
- style={[
254
- styles.lineHorizontal,
255
- {
256
- backgroundColor: lineActive,
257
- },
258
- date ? { marginTop: 27 } : { marginTop: 27 - 16 },
259
- /* subtracting spacing from date */
260
- ]}
261
- />
262
- </View>
263
- );
264
- }
265
- return resultComponent;
126
+ return <View style={[styles.line, { backgroundColor: lineColor }]} />;
266
127
  };
267
128
 
268
- circleColumn = (value, index) => {
269
- const {
270
- currentStep,
271
- titles,
272
- iconActive,
273
- iconChecked,
274
- iconUnchecked,
275
- circleColorActive,
276
- circleColorChecked,
277
- circleColorUnchecked,
278
- circleBorderColorActive,
279
- circleBorderColorChecked,
280
- circleBorderColorUnchecked,
281
- lineColorActive,
282
- lineColorInActive,
283
- items,
284
- date,
285
- isVertical,
286
- titleStyle,
287
- descriptionStyle,
288
- dateStyle,
289
- } = this.props;
290
-
291
- // Three circle states
292
- const isActiveState = currentStep == index + 1;
293
- const circleChecked = currentStep > index + 1;
294
- const circleUnchecked = currentStep < index + 1;
295
-
296
- // Default properties is inactive state
297
- let icon = {};
298
- let circleColor = circleColorUnchecked || Colors.black_06;
299
- let circleBorderColor = circleBorderColorUnchecked || Colors.black_04;
300
- let textFontStyle = styles.titleDefault;
301
- let lineActive = lineColorInActive || Colors.black_04;
302
- let minHeight = !isVertical && styles.minHeight;
303
- let accessibilityLabel = 'uncheck';
304
- let tintColor = '#ffd6e7';
305
-
306
- // This is all properties in active state
307
- if (isActiveState) {
308
- icon = iconActive || index + 1;
309
- circleColor = circleColorActive || '#d82d8b';
310
- circleBorderColor = circleBorderColorActive || Colors.pink_09;
311
- textFontStyle = styles.titleActive;
312
- accessibilityLabel = 'checking';
313
- }
314
-
315
- if (circleChecked) {
316
- icon = iconChecked || IconSource.ic_check_24;
317
- lineActive = lineColorActive || tintColor;
318
- circleColor = circleColorChecked || '#ffadd2';
319
- circleBorderColor = circleBorderColorChecked || Colors.pink_09;
320
- accessibilityLabel = 'checked';
321
- }
322
-
323
- if (circleUnchecked) {
324
- icon = iconUnchecked || index + 1;
325
- }
326
-
327
- const lineWidth = Math.round(
328
- (SCREEN_WIDTH - 10 - CIRCLE_SIZE - 4) / titles.length,
329
- );
330
- const lineRight = parseInt(`-${lineWidth / 2}`);
331
-
129
+ const renderStepPart = (item, index) => {
130
+ const { title, subTitle, content, error } = item;
131
+ const weight = index === currentStep ? '600' : '400';
132
+ const disabledColor = Colors.black_09;
133
+ const errorColor = Colors.error;
332
134
  return (
333
- <View
334
- key={index}
335
- style={{
336
- flexDirection: 'row',
337
- flex: 1,
338
- justifyContent: 'center',
339
- width: lineWidth,
340
- // backgroundColor: 'red'
341
- }}>
135
+ <View key={index.toString()} style={styles.stepPart}>
136
+ <Text
137
+ style={[
138
+ styles.subTitle,
139
+ {
140
+ fontSize: SUBTITLE_SIZE.size,
141
+ lineHeight: SUBTITLE_SIZE.lineHeight,
142
+ color:
143
+ index < currentStep && !error
144
+ ? disabledColor
145
+ : Colors.black_12,
146
+ },
147
+ ]}>
148
+ {subTitle}
149
+ </Text>
342
150
  <View
343
- accessibilityLabel={accessibilityLabel}
344
151
  style={{
345
- flexDirection: 'column',
152
+ flexDirection: 'row',
346
153
  alignItems: 'center',
347
154
  }}>
348
- {this._renderDateOrValue({
349
- date,
350
- isActiveState,
351
- circleChecked,
352
- minHeight,
353
- dateStyle,
354
- index,
355
- })}
356
- {this._renderCircle({
357
- circleColor,
358
- circleBorderColor,
359
- isActiveState,
360
- circleUnchecked,
361
- iconActive,
362
- iconUnchecked,
363
- icon,
364
- index,
365
- })}
366
- {this._renderTitle({
367
- textFontStyle,
368
- titleStyle,
369
- value,
370
- })}
371
- {this._renderDescription({
372
- items,
373
- descriptionStyle,
374
- index,
375
- })}
155
+ {renderLine(index - 1)}
156
+ {renderCircle(error, index)}
157
+ {renderLine(index)}
376
158
  </View>
377
- {this._renderLine({
378
- titles,
379
- index,
380
- lineRight,
381
- lineWidth,
382
- lineActive,
383
- date,
384
- })}
159
+ <Text
160
+ style={[
161
+ styles.title,
162
+ {
163
+ lineHeight: TITLE_SIZE.lineHeight,
164
+ fontSize: TITLE_SIZE.size,
165
+ fontWeight: weight,
166
+ color: error
167
+ ? errorColor
168
+ : index < currentStep
169
+ ? disabledColor
170
+ : null,
171
+ },
172
+ ]}>
173
+ {title}
174
+ </Text>
175
+ <Text
176
+ style={[
177
+ styles.contentText,
178
+ {
179
+ fontSize: CONTENT_SIZE.size,
180
+ lineHeight: CONTENT_SIZE.lineHeight,
181
+ color:
182
+ index < currentStep && !error
183
+ ? disabledColor
184
+ : Colors.black_12,
185
+ },
186
+ ]}>
187
+ {content}
188
+ </Text>
385
189
  </View>
386
190
  );
387
191
  };
388
192
 
389
- renderCircle = () => {
390
- const { titles = [[]] } = this.props;
391
- return titles.map(this.circleColumn);
392
- };
393
-
394
- render() {
395
- const { style = {} } = this.props;
396
- return (
397
- <View style={[style]} onLayout={this.onLayout}>
398
- <View
399
- style={{
400
- flexDirection: 'row',
401
- }}>
402
- {this.renderCircle()}
403
- </View>
193
+ return (
194
+ <View style={style}>
195
+ <View style={styles.container}>
196
+ {steps.map((item, index) => {
197
+ return renderStepPart(item, index);
198
+ })}
404
199
  </View>
405
- );
406
- }
407
- }
408
-
409
- HorizontalStep.propTypes = {
410
- titles: PropTypes.array,
411
- currentStep: PropTypes.number,
412
- style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
413
- items: PropTypes.array,
414
- isVertical: PropTypes.bool,
415
- iconActive: PropTypes.any,
416
- iconChecked: PropTypes.any,
417
- iconUnchecked: PropTypes.any,
418
- circleColorActive: PropTypes.string,
419
- circleColorChecked: PropTypes.string,
420
- circleColorUnchecked: PropTypes.string,
421
- circleBorderColorActive: PropTypes.string,
422
- circleBorderColorChecked: PropTypes.string,
423
- circleBorderColorUnchecked: PropTypes.string,
424
- lineColorActive: PropTypes.string,
425
- lineColorInActive: PropTypes.string,
426
- titleStyle: PropTypes.object,
427
- descriptionStyle: PropTypes.object,
428
- dateStyle: PropTypes.object,
200
+ </View>
201
+ );
429
202
  };
430
203
 
431
- HorizontalStep.defaultProps = {
432
- titles: [],
433
- currentStep: 0,
434
- };
204
+ export default HorizontalStep;
205
+
206
+ const styles = StyleSheet.create({
207
+ container: { flexDirection: 'row', width: '100%' },
208
+ circleContainer: {
209
+ flexDirection: 'column',
210
+ alignItems: 'center',
211
+ height: '100%',
212
+ },
213
+ circle: {
214
+ borderWidth: 2,
215
+ justifyContent: 'center',
216
+ alignItems: 'center',
217
+ margin: Spacing.XS,
218
+ },
219
+ contentContainer: { marginLeft: Spacing.S, flex: 1 },
220
+ content: { marginVertical: Spacing.XS },
221
+ contentText: {
222
+ color: Colors.black_12,
223
+ },
224
+ header: {
225
+ flexDirection: 'row',
226
+ justifyContent: 'space-between',
227
+ alignItems: 'center',
228
+ },
229
+ title: {
230
+ marginBottom: Spacing.XS,
231
+ },
232
+ subTitle: {
233
+ color: Colors.black_12,
234
+ },
235
+ line: {
236
+ height: 2,
237
+ borderRadius: 1,
238
+ flex: 1,
239
+ },
240
+ icon: {
241
+ tintColor: Colors.white,
242
+ },
243
+ circleText: {
244
+ color: Colors.white,
245
+ fontWeight: '600',
246
+ },
247
+ stepPart: {
248
+ flexDirection: 'column',
249
+ alignItems: 'center',
250
+ flex: 1,
251
+ },
252
+ });