unicorn-demo-app 6.25.0 → 6.26.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/package.json +1 -1
- package/src/screens/ExampleScreenPresenter.tsx +44 -10
- package/src/screens/MenuStructure.js +1 -0
- package/src/screens/componentScreens/NumberInputScreen.tsx +230 -0
- package/src/screens/componentScreens/SectionsWheelPickerScreen.tsx +135 -55
- package/src/screens/componentScreens/index.js +1 -0
- package/src/screens/incubatorScreens/IncubatorTextFieldScreen.tsx +1 -6
package/package.json
CHANGED
|
@@ -25,6 +25,13 @@ interface RadioGroupOptions {
|
|
|
25
25
|
interface BooleanGroupOptions {
|
|
26
26
|
spread?: boolean;
|
|
27
27
|
afterValueChanged?: () => void;
|
|
28
|
+
state?: boolean;
|
|
29
|
+
setState?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface SegmentsExtraOptions {
|
|
33
|
+
state?: string;
|
|
34
|
+
setState?: React.Dispatch<React.SetStateAction<any /** no suitable solution for enum */>>;
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
export function renderHeader(title: string, others?: TextProps) {
|
|
@@ -35,19 +42,29 @@ export function renderHeader(title: string, others?: TextProps) {
|
|
|
35
42
|
);
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
export function renderBooleanOption(title: string,
|
|
45
|
+
export function renderBooleanOption(title: string,
|
|
46
|
+
key: string,
|
|
47
|
+
{spread, afterValueChanged, state, setState}: BooleanGroupOptions = {spread: true}) {
|
|
39
48
|
// @ts-ignore
|
|
40
|
-
const value = this.state[key];
|
|
49
|
+
const value = state ?? this.state[key];
|
|
41
50
|
return (
|
|
42
51
|
<View row centerV spread={spread} marginB-s4 key={key}>
|
|
43
|
-
<Text $textDefault flex={spread} marginR-s4={!spread}>
|
|
52
|
+
<Text $textDefault flex={spread} marginR-s4={!spread}>
|
|
53
|
+
{title}
|
|
54
|
+
</Text>
|
|
44
55
|
<Switch
|
|
45
56
|
useCustomTheme
|
|
46
57
|
key={key}
|
|
47
58
|
testID={key}
|
|
48
59
|
value={value}
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
onValueChange={value => {
|
|
61
|
+
if (setState) {
|
|
62
|
+
setState(value);
|
|
63
|
+
} else {
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
this.setState({[key]: value}, afterValueChanged);
|
|
66
|
+
}
|
|
67
|
+
}}
|
|
51
68
|
/>
|
|
52
69
|
</View>
|
|
53
70
|
);
|
|
@@ -130,7 +147,9 @@ export function renderColorOption(title: string,
|
|
|
130
147
|
const value = this.state[key];
|
|
131
148
|
return (
|
|
132
149
|
<View marginV-s2>
|
|
133
|
-
<Text text70M $textDefault>
|
|
150
|
+
<Text text70M $textDefault>
|
|
151
|
+
{title}
|
|
152
|
+
</Text>
|
|
134
153
|
<ColorPalette
|
|
135
154
|
value={value}
|
|
136
155
|
colors={colors}
|
|
@@ -171,19 +190,34 @@ export function renderSliderOption(title: string,
|
|
|
171
190
|
);
|
|
172
191
|
}
|
|
173
192
|
|
|
174
|
-
export function renderMultipleSegmentOptions(title: string,
|
|
193
|
+
export function renderMultipleSegmentOptions(title: string,
|
|
194
|
+
key: string,
|
|
195
|
+
options: (SegmentedControlItemProps & {value: any})[],
|
|
196
|
+
{state, setState}: SegmentsExtraOptions = {}) {
|
|
175
197
|
// @ts-ignore
|
|
176
|
-
const value = this.state[key];
|
|
198
|
+
const value = state ?? this.state[key];
|
|
177
199
|
const index = _.findIndex(options, {value});
|
|
178
200
|
|
|
179
201
|
return (
|
|
180
202
|
<View row centerV spread marginB-s4 key={key}>
|
|
181
|
-
{!!title &&
|
|
203
|
+
{!!title && (
|
|
204
|
+
<Text $textDefault marginR-s2>
|
|
205
|
+
{title}
|
|
206
|
+
</Text>
|
|
207
|
+
)}
|
|
182
208
|
<SegmentedControl
|
|
183
209
|
initialIndex={index}
|
|
184
210
|
segments={options}
|
|
185
211
|
// @ts-ignore
|
|
186
|
-
onChangeIndex={index =>
|
|
212
|
+
onChangeIndex={index => {
|
|
213
|
+
const value = options[index].value;
|
|
214
|
+
if (setState) {
|
|
215
|
+
setState(value);
|
|
216
|
+
} else {
|
|
217
|
+
// @ts-ignore
|
|
218
|
+
this.setState({[key]: value});
|
|
219
|
+
}
|
|
220
|
+
}}
|
|
187
221
|
/>
|
|
188
222
|
</View>
|
|
189
223
|
);
|
|
@@ -54,6 +54,7 @@ export const navigationData = {
|
|
|
54
54
|
{title: 'Color Picker', tags: 'color picker control', screen: 'unicorn.components.ColorPickerScreen'},
|
|
55
55
|
{title: 'Color Swatch', tags: 'color swatch and palette', screen: 'unicorn.components.ColorSwatchScreen'},
|
|
56
56
|
{title: 'TextField', tags: 'text input field form', screen: 'unicorn.components.TextFieldScreen'},
|
|
57
|
+
{title: 'NumberInput', tags: 'number input', screen: 'unicorn.components.NumberInputScreen'},
|
|
57
58
|
{title: 'Picker', tags: 'picker form', screen: 'unicorn.components.PickerScreen'},
|
|
58
59
|
{title: 'DateTimePicker', tags: 'date time picker form', screen: 'unicorn.components.DateTimePickerScreen'},
|
|
59
60
|
{title: 'RadioButton', tags: 'radio button group controls', screen: 'unicorn.components.RadioButtonScreen'},
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import React, {useState, useCallback, useRef, useMemo} from 'react';
|
|
2
|
+
import {StyleSheet, TouchableWithoutFeedback, Keyboard as RNKeyboard} from 'react-native';
|
|
3
|
+
import {gestureHandlerRootHOC} from 'react-native-gesture-handler';
|
|
4
|
+
import {
|
|
5
|
+
Text,
|
|
6
|
+
Spacings,
|
|
7
|
+
NumberInput,
|
|
8
|
+
NumberInputData,
|
|
9
|
+
View,
|
|
10
|
+
Typography,
|
|
11
|
+
Constants,
|
|
12
|
+
Incubator
|
|
13
|
+
} from 'react-native-ui-lib';
|
|
14
|
+
import {renderBooleanOption, renderMultipleSegmentOptions} from '../ExampleScreenPresenter';
|
|
15
|
+
|
|
16
|
+
enum ExampleTypeEnum {
|
|
17
|
+
PRICE = 'price',
|
|
18
|
+
PERCENTAGE = 'percentage',
|
|
19
|
+
ANY_NUMBER = 'number'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type ExampleType = ExampleTypeEnum | `${ExampleTypeEnum}`;
|
|
23
|
+
|
|
24
|
+
const VALIDATION_MESSAGE = 'Please enter a valid number';
|
|
25
|
+
const MINIMUM_PRICE = 5000;
|
|
26
|
+
const MINIMUM_PRICE_VALIDATION_MESSAGE = `Make sure your number is above ${MINIMUM_PRICE}`;
|
|
27
|
+
const DISCOUNT_PERCENTAGE = {min: 1, max: 80};
|
|
28
|
+
// eslint-disable-next-line max-len
|
|
29
|
+
const DISCOUNT_PERCENTAGE_VALIDATION_MESSAGE = `Make sure your number is between ${DISCOUNT_PERCENTAGE.min} and ${DISCOUNT_PERCENTAGE.max}`;
|
|
30
|
+
|
|
31
|
+
const NumberInputScreen = () => {
|
|
32
|
+
const currentData = useRef<NumberInputData>();
|
|
33
|
+
const [text, setText] = useState<string>('');
|
|
34
|
+
const [showLabel, setShowLabel] = useState<boolean>(true);
|
|
35
|
+
const [exampleType, setExampleType] = useState<ExampleType>('price');
|
|
36
|
+
|
|
37
|
+
const processInput = useCallback(() => {
|
|
38
|
+
let newText = '';
|
|
39
|
+
if (currentData.current) {
|
|
40
|
+
switch (currentData.current.type) {
|
|
41
|
+
case 'valid':
|
|
42
|
+
newText = currentData.current.formattedNumber;
|
|
43
|
+
break;
|
|
44
|
+
case 'empty':
|
|
45
|
+
newText = 'Empty';
|
|
46
|
+
break;
|
|
47
|
+
case 'error':
|
|
48
|
+
newText = `Error: value '${currentData.current.userInput}' is invalid`;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setText(newText);
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
const onChangeNumber = useCallback((data: NumberInputData) => {
|
|
57
|
+
currentData.current = data;
|
|
58
|
+
processInput();
|
|
59
|
+
},
|
|
60
|
+
[processInput]);
|
|
61
|
+
|
|
62
|
+
const label = useMemo(() => {
|
|
63
|
+
if (showLabel) {
|
|
64
|
+
switch (exampleType) {
|
|
65
|
+
case 'price':
|
|
66
|
+
default:
|
|
67
|
+
return 'Enter price';
|
|
68
|
+
case 'percentage':
|
|
69
|
+
return 'Enter discount percentage';
|
|
70
|
+
case 'number':
|
|
71
|
+
return 'Enter any number';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, [showLabel, exampleType]);
|
|
75
|
+
|
|
76
|
+
const placeholder = useMemo(() => {
|
|
77
|
+
switch (exampleType) {
|
|
78
|
+
case 'price':
|
|
79
|
+
default:
|
|
80
|
+
return 'Price';
|
|
81
|
+
case 'percentage':
|
|
82
|
+
return 'Discount';
|
|
83
|
+
case 'number':
|
|
84
|
+
return 'Any number';
|
|
85
|
+
}
|
|
86
|
+
}, [exampleType]);
|
|
87
|
+
|
|
88
|
+
const fractionDigits = useMemo(() => {
|
|
89
|
+
switch (exampleType) {
|
|
90
|
+
case 'price':
|
|
91
|
+
case 'number':
|
|
92
|
+
default:
|
|
93
|
+
return undefined;
|
|
94
|
+
case 'percentage':
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
}, [exampleType]);
|
|
98
|
+
|
|
99
|
+
const leadingText = useMemo(() => {
|
|
100
|
+
switch (exampleType) {
|
|
101
|
+
case 'price':
|
|
102
|
+
return '$';
|
|
103
|
+
case 'percentage':
|
|
104
|
+
case 'number':
|
|
105
|
+
default:
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
}, [exampleType]);
|
|
109
|
+
|
|
110
|
+
const trailingText = useMemo(() => {
|
|
111
|
+
switch (exampleType) {
|
|
112
|
+
case 'percentage':
|
|
113
|
+
return '%';
|
|
114
|
+
case 'price':
|
|
115
|
+
case 'number':
|
|
116
|
+
default:
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
}, [exampleType]);
|
|
120
|
+
|
|
121
|
+
const isValid = useCallback(() => {
|
|
122
|
+
return currentData.current?.type === 'valid';
|
|
123
|
+
}, []);
|
|
124
|
+
|
|
125
|
+
const isAboveMinimumPrice = useCallback(() => {
|
|
126
|
+
if (currentData.current?.type === 'valid') {
|
|
127
|
+
return currentData.current.number > MINIMUM_PRICE;
|
|
128
|
+
}
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
const isWithinDiscountPercentage = useCallback(() => {
|
|
132
|
+
if (currentData.current?.type === 'valid') {
|
|
133
|
+
return (
|
|
134
|
+
currentData.current.number >= DISCOUNT_PERCENTAGE.min && currentData.current.number <= DISCOUNT_PERCENTAGE.max
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}, []);
|
|
138
|
+
|
|
139
|
+
const validate = useMemo((): Incubator.TextFieldProps['validate'] => {
|
|
140
|
+
switch (exampleType) {
|
|
141
|
+
case 'price':
|
|
142
|
+
return [isValid, isAboveMinimumPrice];
|
|
143
|
+
case 'percentage':
|
|
144
|
+
return [isValid, isWithinDiscountPercentage];
|
|
145
|
+
default:
|
|
146
|
+
return isValid;
|
|
147
|
+
}
|
|
148
|
+
}, [exampleType, isValid, isAboveMinimumPrice, isWithinDiscountPercentage]);
|
|
149
|
+
|
|
150
|
+
const validationMessage = useMemo((): Incubator.TextFieldProps['validationMessage'] => {
|
|
151
|
+
switch (exampleType) {
|
|
152
|
+
case 'price':
|
|
153
|
+
return [VALIDATION_MESSAGE, MINIMUM_PRICE_VALIDATION_MESSAGE];
|
|
154
|
+
case 'percentage':
|
|
155
|
+
return [VALIDATION_MESSAGE, DISCOUNT_PERCENTAGE_VALIDATION_MESSAGE];
|
|
156
|
+
default:
|
|
157
|
+
return VALIDATION_MESSAGE;
|
|
158
|
+
}
|
|
159
|
+
}, [exampleType]);
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<TouchableWithoutFeedback onPress={RNKeyboard.dismiss}>
|
|
163
|
+
<View flex centerH>
|
|
164
|
+
<Text text40 margin-s10>
|
|
165
|
+
Number Input
|
|
166
|
+
</Text>
|
|
167
|
+
{renderBooleanOption('Show label', 'showLabel', {spread: false, state: showLabel, setState: setShowLabel})}
|
|
168
|
+
{renderMultipleSegmentOptions('',
|
|
169
|
+
'exampleType',
|
|
170
|
+
[
|
|
171
|
+
{label: 'Price', value: ExampleTypeEnum.PRICE},
|
|
172
|
+
{label: 'Percentage', value: ExampleTypeEnum.PERCENTAGE},
|
|
173
|
+
{label: 'Number', value: ExampleTypeEnum.ANY_NUMBER}
|
|
174
|
+
],
|
|
175
|
+
{state: exampleType, setState: setExampleType})}
|
|
176
|
+
|
|
177
|
+
<View flex center>
|
|
178
|
+
<NumberInput
|
|
179
|
+
key={exampleType}
|
|
180
|
+
// initialNumber={100}
|
|
181
|
+
label={label}
|
|
182
|
+
labelStyle={styles.label}
|
|
183
|
+
placeholder={placeholder}
|
|
184
|
+
fractionDigits={fractionDigits}
|
|
185
|
+
onChangeNumber={onChangeNumber}
|
|
186
|
+
leadingText={leadingText}
|
|
187
|
+
leadingTextStyle={leadingText && [styles.infoText, {marginLeft: Spacings.s4}]}
|
|
188
|
+
trailingText={trailingText}
|
|
189
|
+
trailingTextStyle={trailingText && [styles.infoText, {marginRight: Spacings.s4}]}
|
|
190
|
+
style={[
|
|
191
|
+
styles.mainText,
|
|
192
|
+
!leadingText && {marginLeft: Spacings.s4},
|
|
193
|
+
!trailingText && {marginRight: Spacings.s4}
|
|
194
|
+
]}
|
|
195
|
+
containerStyle={styles.containerStyle}
|
|
196
|
+
validate={validate}
|
|
197
|
+
validationMessage={validationMessage}
|
|
198
|
+
validationMessageStyle={Typography.text80M}
|
|
199
|
+
validateOnChange
|
|
200
|
+
centered
|
|
201
|
+
/>
|
|
202
|
+
<Text marginT-s5>{text}</Text>
|
|
203
|
+
</View>
|
|
204
|
+
</View>
|
|
205
|
+
</TouchableWithoutFeedback>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default gestureHandlerRootHOC(NumberInputScreen);
|
|
210
|
+
|
|
211
|
+
const styles = StyleSheet.create({
|
|
212
|
+
containerStyle: {
|
|
213
|
+
marginBottom: 30,
|
|
214
|
+
marginLeft: Spacings.s5,
|
|
215
|
+
marginRight: Spacings.s5
|
|
216
|
+
},
|
|
217
|
+
mainText: {
|
|
218
|
+
height: 36,
|
|
219
|
+
marginVertical: Spacings.s1,
|
|
220
|
+
...Typography.text30M
|
|
221
|
+
},
|
|
222
|
+
infoText: {
|
|
223
|
+
marginTop: Constants.isIOS ? Spacings.s2 : 0,
|
|
224
|
+
...Typography.text50M
|
|
225
|
+
},
|
|
226
|
+
label: {
|
|
227
|
+
marginBottom: Spacings.s1,
|
|
228
|
+
...Typography.text80M
|
|
229
|
+
}
|
|
230
|
+
});
|
|
@@ -1,37 +1,52 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
|
-
import React, {useState, useCallback} from 'react';
|
|
3
|
-
import {Alert} from 'react-native';
|
|
4
|
-
import {
|
|
2
|
+
import React, {useState, useCallback, useMemo} from 'react';
|
|
3
|
+
import {Alert, StyleSheet} from 'react-native';
|
|
4
|
+
import {
|
|
5
|
+
Text,
|
|
6
|
+
View,
|
|
7
|
+
SectionsWheelPicker,
|
|
8
|
+
SegmentedControl,
|
|
9
|
+
Button,
|
|
10
|
+
Incubator,
|
|
11
|
+
Constants,
|
|
12
|
+
Switch,
|
|
13
|
+
Colors
|
|
14
|
+
} from 'react-native-ui-lib';
|
|
5
15
|
|
|
6
16
|
const {WheelPicker} = Incubator;
|
|
17
|
+
|
|
18
|
+
const DAYS = _.times(10, i => i);
|
|
19
|
+
const HOURS = _.times(24, i => i);
|
|
20
|
+
const MINUTES = _.times(60, i => i);
|
|
21
|
+
|
|
7
22
|
const SectionsWheelPickerScreen = () => {
|
|
8
23
|
const [numOfSections, setNumOfSections] = useState(1);
|
|
9
|
-
|
|
24
|
+
const [disableRTL, setDisableRTL] = useState(false);
|
|
10
25
|
const [selectedDays, setSelectedDays] = useState(0);
|
|
11
26
|
const [selectedHours, setSelectedHours] = useState(0);
|
|
12
27
|
const [selectedMinutes, setSelectedMinutes] = useState(0);
|
|
13
28
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
29
|
+
const shouldDisableRTL = useMemo(() => {
|
|
30
|
+
return Constants.isRTL && disableRTL;
|
|
31
|
+
}, [disableRTL]);
|
|
17
32
|
|
|
18
33
|
const getItems = useCallback(values => {
|
|
19
34
|
return _.map(values, item => ({label: '' + item, value: item}));
|
|
20
35
|
}, []);
|
|
21
36
|
|
|
22
|
-
const onDaysChange = (item: number | string) => {
|
|
37
|
+
const onDaysChange = useCallback((item: number | string) => {
|
|
23
38
|
setSelectedDays(item as number);
|
|
24
|
-
};
|
|
39
|
+
}, []);
|
|
25
40
|
|
|
26
|
-
const onHoursChange = (item: number | string) => {
|
|
41
|
+
const onHoursChange = useCallback((item: number | string) => {
|
|
27
42
|
setSelectedHours(item as number);
|
|
28
|
-
};
|
|
43
|
+
}, []);
|
|
29
44
|
|
|
30
|
-
const onMinutesChange = (item: number | string) => {
|
|
45
|
+
const onMinutesChange = useCallback((item: number | string) => {
|
|
31
46
|
setSelectedMinutes(item as number);
|
|
32
|
-
};
|
|
47
|
+
}, []);
|
|
33
48
|
|
|
34
|
-
const onSavePress = () => {
|
|
49
|
+
const onSavePress = useCallback(() => {
|
|
35
50
|
const days = selectedDays === 1 ? 'day' : 'days';
|
|
36
51
|
const hours = selectedHours === 1 ? 'hour' : 'hours';
|
|
37
52
|
const minutes = selectedMinutes === 1 ? 'minute' : 'minutes';
|
|
@@ -52,67 +67,132 @@ const SectionsWheelPickerScreen = () => {
|
|
|
52
67
|
: numOfSections === 2
|
|
53
68
|
? Alert.alert('Your chosen duration is:\n' + selectedDays + ' ' + days + ' and ' + selectedHours + ' ' + hours)
|
|
54
69
|
: Alert.alert('Your chosen duration is:\n' + selectedDays + ' ' + days);
|
|
55
|
-
};
|
|
70
|
+
}, [numOfSections, selectedDays, selectedHours, selectedMinutes]);
|
|
56
71
|
|
|
57
|
-
const onResetPress = () => {
|
|
72
|
+
const onResetPress = useCallback(() => {
|
|
58
73
|
setSelectedDays(0);
|
|
59
74
|
setSelectedHours(0);
|
|
60
75
|
setSelectedMinutes(0);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const sections: Incubator.WheelPickerProps[] =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
const sections: Incubator.WheelPickerProps[] = useMemo(() => {
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
items: getItems(DAYS),
|
|
82
|
+
onChange: onDaysChange,
|
|
83
|
+
initialValue: selectedDays,
|
|
84
|
+
label: Constants.isRTL ? 'ימים' : 'Days',
|
|
85
|
+
align:
|
|
86
|
+
numOfSections === 1
|
|
87
|
+
? WheelPicker.alignments.CENTER
|
|
88
|
+
: shouldDisableRTL
|
|
89
|
+
? WheelPicker.alignments.LEFT
|
|
90
|
+
: WheelPicker.alignments.RIGHT,
|
|
91
|
+
style: {
|
|
92
|
+
flex: 1,
|
|
93
|
+
flexDirection: numOfSections !== 1 && Constants.isRTL && !disableRTL ? 'row-reverse' : undefined
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
items: getItems(HOURS),
|
|
98
|
+
onChange: onHoursChange,
|
|
99
|
+
initialValue: selectedHours,
|
|
100
|
+
label: Constants.isRTL ? 'שעות' : 'Hrs',
|
|
101
|
+
align:
|
|
102
|
+
numOfSections === 2
|
|
103
|
+
? shouldDisableRTL
|
|
104
|
+
? WheelPicker.alignments.RIGHT
|
|
105
|
+
: WheelPicker.alignments.LEFT
|
|
106
|
+
: WheelPicker.alignments.CENTER,
|
|
107
|
+
style: numOfSections === 2 ? {flex: 1, flexDirection: shouldDisableRTL ? 'row-reverse' : 'row'} : undefined
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
items: getItems(MINUTES),
|
|
111
|
+
onChange: onMinutesChange,
|
|
112
|
+
initialValue: selectedMinutes,
|
|
113
|
+
label: Constants.isRTL ? 'דקות' : 'Mins',
|
|
114
|
+
align: shouldDisableRTL ? WheelPicker.alignments.RIGHT : WheelPicker.alignments.LEFT,
|
|
115
|
+
style: {flex: 1, flexDirection: shouldDisableRTL ? 'row-reverse' : 'row'}
|
|
116
|
+
}
|
|
117
|
+
];
|
|
118
|
+
}, [
|
|
119
|
+
getItems,
|
|
120
|
+
disableRTL,
|
|
121
|
+
selectedDays,
|
|
122
|
+
selectedHours,
|
|
123
|
+
selectedMinutes,
|
|
124
|
+
onDaysChange,
|
|
125
|
+
onHoursChange,
|
|
126
|
+
onMinutesChange,
|
|
127
|
+
numOfSections,
|
|
128
|
+
shouldDisableRTL
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
const sectionsToPresent = useMemo(() => _.slice(sections, 0, numOfSections), [numOfSections, sections]);
|
|
132
|
+
|
|
133
|
+
const timeSections = useMemo(() => {
|
|
134
|
+
return [
|
|
135
|
+
{
|
|
136
|
+
items: getItems(_.times(24, i => i + 1))
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
items: getItems(_.times(12, i => {
|
|
140
|
+
if (i < 2) {
|
|
141
|
+
return `0${i * 5}`;
|
|
142
|
+
}
|
|
143
|
+
return i * 5;
|
|
144
|
+
}))
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
}, [getItems]);
|
|
148
|
+
|
|
149
|
+
const onChangeIndex = useCallback((index: number) => {
|
|
93
150
|
return setNumOfSections(index + 1);
|
|
94
|
-
};
|
|
151
|
+
}, []);
|
|
152
|
+
|
|
153
|
+
const updateDisableRTLValue = useCallback((value: boolean) => {
|
|
154
|
+
setDisableRTL(value);
|
|
155
|
+
}, []);
|
|
95
156
|
|
|
96
157
|
return (
|
|
97
158
|
<View>
|
|
98
159
|
<Text text40 marginL-10 marginT-20>
|
|
99
160
|
Sections Wheel Picker
|
|
100
161
|
</Text>
|
|
101
|
-
<View
|
|
162
|
+
<View row center style={styles.bottomDivider}>
|
|
163
|
+
<Text margin-s5> Disable RTL</Text>
|
|
164
|
+
<Switch value={shouldDisableRTL} onValueChange={updateDisableRTLValue}/>
|
|
165
|
+
</View>
|
|
166
|
+
<View centerH marginT-20>
|
|
167
|
+
<Text text60 marginB-20>
|
|
168
|
+
Pick a duration
|
|
169
|
+
</Text>
|
|
102
170
|
<SegmentedControl
|
|
103
171
|
segments={[{label: '1 section'}, {label: '2 sections'}, {label: '3 sections'}]}
|
|
104
172
|
onChangeIndex={onChangeIndex}
|
|
105
173
|
throttleTime={400}
|
|
106
174
|
/>
|
|
107
|
-
|
|
108
|
-
|
|
175
|
+
</View>
|
|
176
|
+
<SectionsWheelPicker numberOfVisibleRows={4} disableRTL={disableRTL} sections={sectionsToPresent}/>
|
|
177
|
+
<View paddingB-20 center spread row style={styles.bottomDivider}>
|
|
178
|
+
<Button marginR-40 link label={'Save'} onPress={onSavePress}/>
|
|
179
|
+
<Button label={'Reset'} link onPress={onResetPress}/>
|
|
180
|
+
</View>
|
|
181
|
+
<View>
|
|
182
|
+
<Text center text60 marginV-20>
|
|
183
|
+
Pick a time
|
|
109
184
|
</Text>
|
|
185
|
+
<SectionsWheelPicker disableRTL={disableRTL} sections={timeSections}/>
|
|
110
186
|
</View>
|
|
111
|
-
<SectionsWheelPicker sections={sectionsToPresent}/>
|
|
112
|
-
<Button marginH-150 marginT-40 label={'Save'} onPress={onSavePress}/>
|
|
113
|
-
<Button marginH-150 marginT-15 label={'Reset'} onPress={onResetPress}/>
|
|
114
187
|
</View>
|
|
115
188
|
);
|
|
116
189
|
};
|
|
117
190
|
|
|
118
191
|
export default SectionsWheelPickerScreen;
|
|
192
|
+
|
|
193
|
+
const styles = StyleSheet.create({
|
|
194
|
+
bottomDivider: {
|
|
195
|
+
borderBottomColor: Colors.$outlineDefault,
|
|
196
|
+
borderBottomWidth: 4
|
|
197
|
+
}
|
|
198
|
+
});
|
|
@@ -31,6 +31,7 @@ export function registerScreens(registrar) {
|
|
|
31
31
|
registrar('unicorn.components.KeyboardAwareScrollViewScreen', () => require('./KeyboardAwareScrollViewScreen').default);
|
|
32
32
|
registrar('unicorn.components.MaskedInputScreen', () => require('./MaskedInputScreen').default);
|
|
33
33
|
registrar('unicorn.components.MarqueeScreen', () => require('./MarqueeScreen').default);
|
|
34
|
+
registrar('unicorn.components.NumberInputScreen', () => require('./NumberInputScreen').default);
|
|
34
35
|
registrar('unicorn.components.OverlaysScreen', () => require('./OverlaysScreen').default);
|
|
35
36
|
registrar('unicorn.components.PageControlScreen', () => require('./PageControlScreen').default);
|
|
36
37
|
registrar('unicorn.components.PanDismissibleScreen', () => require('./PanDismissibleScreen').default);
|
|
@@ -277,12 +277,7 @@ export default class TextFieldScreen extends Component {
|
|
|
277
277
|
Centered
|
|
278
278
|
</Text>
|
|
279
279
|
|
|
280
|
-
<TextField
|
|
281
|
-
label="PIN"
|
|
282
|
-
placeholder="XXXX"
|
|
283
|
-
labelStyle={{alignSelf: 'center'}}
|
|
284
|
-
containerStyle={{alignSelf: 'center'}}
|
|
285
|
-
/>
|
|
280
|
+
<TextField label="PIN" placeholder="XXXX" centered/>
|
|
286
281
|
</View>
|
|
287
282
|
<KeyboardAwareInsetsView/>
|
|
288
283
|
</ScrollView>
|