@hero-design/rn 7.5.0 → 7.6.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/.turbo/turbo-build.log +8 -8
- package/es/index.js +474 -110
- package/lib/index.js +474 -108
- package/package.json +2 -2
- package/playground/.turbo/turbo-type-check.log +7 -0
- package/playground/package.json +3 -3
- package/playground/src/App.tsx +6 -0
- package/playground/src/ContentNavigator.tsx +3 -10
- package/playground/src/Select.tsx +32 -0
- package/playground/src/Switch.tsx +80 -0
- package/src/components/BottomSheet/Header.tsx +1 -1
- package/src/components/BottomSheet/__tests__/__snapshots__/index.spec.tsx.snap +8 -8
- package/src/components/BottomSheet/index.tsx +6 -0
- package/src/components/Radio/RadioGroup.tsx +31 -7
- package/src/components/Radio/types.ts +1 -0
- package/src/components/SectionHeading/StyledHeading.tsx +5 -5
- package/src/components/SectionHeading/__tests__/{StyledHeading.tsx → StyledHeading.spec.tsx} +0 -0
- package/src/components/SectionHeading/__tests__/__snapshots__/{StyledHeading.tsx.snap → StyledHeading.spec.tsx.snap} +0 -0
- package/src/components/Select/MultiSelect/Footer.tsx +15 -0
- package/src/components/Select/MultiSelect/OptionList.tsx +76 -0
- package/src/components/Select/MultiSelect/StyledMultiSelect.tsx +30 -0
- package/src/components/Select/MultiSelect/__tests__/StyledMultiSelect.spec.tsx +49 -0
- package/src/components/Select/MultiSelect/__tests__/__snapshots__/StyledMultiSelect.spec.tsx.snap +108 -0
- package/src/components/Select/MultiSelect/__tests__/__snapshots__/index.spec.tsx.snap +1630 -0
- package/src/components/Select/MultiSelect/__tests__/index.spec.tsx +94 -0
- package/src/components/Select/MultiSelect/index.tsx +103 -0
- package/src/components/Select/MultiSelect/types.ts +1 -0
- package/src/components/Select/index.tsx +5 -0
- package/src/components/Switch/StyledSwitch.tsx +50 -0
- package/src/components/Switch/__tests__/StyledHeading.spec.tsx +42 -0
- package/src/components/Switch/__tests__/__snapshots__/StyledHeading.spec.tsx.snap +74 -0
- package/src/components/Switch/__tests__/__snapshots__/index.spec.tsx.snap +129 -0
- package/src/components/Switch/__tests__/index.spec.tsx +24 -0
- package/src/components/Switch/index.tsx +87 -0
- package/src/components/TextInput/StyledTextInput.tsx +2 -6
- package/src/components/TextInput/__tests__/StyledTextInput.spec.tsx +1 -7
- package/src/components/TextInput/__tests__/__snapshots__/StyledTextInput.spec.tsx.snap +1 -22
- package/src/components/TextInput/__tests__/index.spec.tsx +2 -1
- package/src/components/TextInput/index.tsx +19 -6
- package/src/index.ts +4 -0
- package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +58 -1
- package/src/theme/components/sectionHeading.ts +18 -0
- package/src/theme/components/select.ts +23 -0
- package/src/theme/components/switch.ts +50 -0
- package/src/theme/components/textInput.ts +1 -1
- package/src/theme/global/colors.ts +1 -0
- package/src/theme/index.ts +12 -3
- package/types/components/BottomSheet/index.d.ts +5 -1
- package/types/components/Radio/RadioGroup.d.ts +11 -8
- package/types/components/Radio/index.d.ts +1 -1
- package/types/components/Radio/types.d.ts +5 -0
- package/types/components/SectionHeading/__tests__/{StyledHeading.d.ts → StyledHeading.spec.d.ts} +0 -0
- package/types/components/Select/MultiSelect/Footer.d.ts +5 -0
- package/types/components/Select/MultiSelect/OptionList.d.ts +3 -0
- package/types/components/Select/MultiSelect/StyledMultiSelect.d.ts +26 -0
- package/types/components/Select/MultiSelect/__tests__/StyledMultiSelect.spec.d.ts +1 -0
- package/types/components/Select/MultiSelect/__tests__/index.spec.d.ts +1 -0
- package/types/components/Select/MultiSelect/index.d.ts +39 -0
- package/types/components/Select/MultiSelect/types.d.ts +5 -0
- package/types/components/Select/index.d.ts +5 -0
- package/types/components/Switch/StyledSwitch.d.ts +36 -0
- package/types/components/Switch/__tests__/StyledHeading.spec.d.ts +1 -0
- package/types/components/Switch/__tests__/index.spec.d.ts +1 -0
- package/types/components/Switch/index.d.ts +30 -0
- package/types/components/TextInput/StyledTextInput.d.ts +1 -5
- package/types/components/TextInput/index.d.ts +13 -5
- package/types/index.d.ts +3 -1
- package/types/theme/components/sectionHeading.d.ts +13 -0
- package/types/theme/components/select.d.ts +17 -0
- package/types/theme/components/switch.d.ts +32 -0
- package/types/theme/components/textInput.d.ts +1 -1
- package/types/theme/global/colors.d.ts +1 -0
- package/types/theme/global/index.d.ts +1 -0
- package/types/theme/index.d.ts +8 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hero-design/rn",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@emotion/native": "^11.9.3",
|
|
27
27
|
"@emotion/react": "^11.9.3",
|
|
28
|
-
"@hero-design/colors": "7.
|
|
28
|
+
"@hero-design/colors": "7.6.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"react": "17.0.2",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
[36m@hero-design/playground:type-check[0m: cache hit, replaying output [2m7c10418dc02a32a7[0m
|
|
2
|
+
[36m@hero-design/playground:type-check: [0mwarning From Yarn 1.0 onwards, scripts don't require "--" for options to be forwarded. In a future version, any explicit "--" will be forwarded as-is to the scripts.
|
|
3
|
+
[36m@hero-design/playground:type-check: [0m$ tsc --noEmit --w
|
|
4
|
+
[36m@hero-design/playground:type-check: [0mc2:47:14 PM - Starting compilation in watch mode...
|
|
5
|
+
[36m@hero-design/playground:type-check: [0m
|
|
6
|
+
[36m@hero-design/playground:type-check: [0m
|
|
7
|
+
[36m@hero-design/playground:type-check: [0m2:47:15 PM - Found 0 errors. Watching for file changes.
|
package/playground/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hero-design/playground",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.6.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"lint": "eslint src expoEntry.js --ext .js,.jsx,.ts,.tsx --ignore-path ../../../.gitignore",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"visual-test": "detox build -c ios.sim.release && detox test -c ios.sim.release"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@hero-design/colors": "7.
|
|
17
|
-
"@hero-design/rn": "7.
|
|
16
|
+
"@hero-design/colors": "7.6.0",
|
|
17
|
+
"@hero-design/rn": "7.6.0",
|
|
18
18
|
"@react-native-community/masked-view": "^0.1.11",
|
|
19
19
|
"@react-navigation/core": "^6.3.0",
|
|
20
20
|
"@react-navigation/native": "^6.0.12",
|
package/playground/src/App.tsx
CHANGED
|
@@ -34,6 +34,8 @@ import ProgressPlayground from './Progress';
|
|
|
34
34
|
import SpinnerPlayground from './Spinner';
|
|
35
35
|
import SectionHeadingPlayground from './SectionHeading';
|
|
36
36
|
import RadioPlayground from './Radio';
|
|
37
|
+
import SelectPlayground from './Select';
|
|
38
|
+
import SwitchPlayground from './Switch';
|
|
37
39
|
import TabsPlayground from './Tabs';
|
|
38
40
|
import TagPlayground from './Tag';
|
|
39
41
|
import TextInputPlayground from './TextInput';
|
|
@@ -65,6 +67,8 @@ type RootStackParamList = {
|
|
|
65
67
|
Spinner: undefined;
|
|
66
68
|
Radio: undefined;
|
|
67
69
|
SectionHeading: undefined;
|
|
70
|
+
Select: undefined;
|
|
71
|
+
Switch: undefined;
|
|
68
72
|
Tabs: undefined;
|
|
69
73
|
Tag: undefined;
|
|
70
74
|
TextInput: undefined;
|
|
@@ -95,6 +99,8 @@ const components = [
|
|
|
95
99
|
{ name: 'Spinner', component: SpinnerPlayground },
|
|
96
100
|
{ name: 'Radio', component: RadioPlayground },
|
|
97
101
|
{ name: 'SectionHeading', component: SectionHeadingPlayground },
|
|
102
|
+
{ name: 'Select', component: SelectPlayground },
|
|
103
|
+
{ name: 'Switch', component: SwitchPlayground },
|
|
98
104
|
{ name: 'Tabs', component: TabsPlayground },
|
|
99
105
|
{ name: 'Tag', component: TagPlayground },
|
|
100
106
|
{ name: 'TextInput', component: TextInputPlayground },
|
|
@@ -24,22 +24,15 @@ function formatDate(date: Date) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const ContentNavigatorPlayground = (): JSX.Element => {
|
|
27
|
-
const
|
|
28
|
-
space: { medium },
|
|
29
|
-
} = useTheme();
|
|
27
|
+
const theme = useTheme();
|
|
30
28
|
const [age, setAge] = useState(20);
|
|
31
29
|
const [date, setDate] = useState(new Date());
|
|
32
30
|
const { monday, sunday } = getMondayAndSunday(date);
|
|
33
31
|
|
|
34
32
|
return (
|
|
35
|
-
<View
|
|
36
|
-
style={{
|
|
37
|
-
marginVertical: medium,
|
|
38
|
-
marginHorizontal: medium,
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
33
|
+
<View style={{ margin: theme.space.medium }}>
|
|
41
34
|
<View style={{ flexDirection: 'row' }}>
|
|
42
|
-
<Typography.Text style={{ paddingRight: medium }}>
|
|
35
|
+
<Typography.Text style={{ paddingRight: theme.space.medium }}>
|
|
43
36
|
Age (18 to 25):
|
|
44
37
|
</Typography.Text>
|
|
45
38
|
<ContentNavigator
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { Select, useTheme } from '@hero-design/rn';
|
|
4
|
+
|
|
5
|
+
const SelectPlayground = (): JSX.Element => {
|
|
6
|
+
const theme = useTheme();
|
|
7
|
+
const options = [
|
|
8
|
+
{ text: 'Monday', value: 'mon' },
|
|
9
|
+
{ text: 'Tuesday', value: 'tue' },
|
|
10
|
+
{ text: 'Wednesday', value: 'wed' },
|
|
11
|
+
{ text: 'Thursday', value: 'thu' },
|
|
12
|
+
{ text: 'Friday', value: 'fri' },
|
|
13
|
+
{ text: 'Saturday', value: 'sat' },
|
|
14
|
+
{ text: 'Sunday', value: 'sun' },
|
|
15
|
+
];
|
|
16
|
+
const [value, setValue] = useState(['mon', 'tue']);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<View style={{ margin: theme.space.medium }}>
|
|
20
|
+
<Select.Multi
|
|
21
|
+
label="Allow notifications"
|
|
22
|
+
footerLabel="Confirm"
|
|
23
|
+
options={options}
|
|
24
|
+
value={value}
|
|
25
|
+
onPress={setValue}
|
|
26
|
+
keyExtractor={opt => opt.value}
|
|
27
|
+
/>
|
|
28
|
+
</View>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default SelectPlayground;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Switch, Typography, useTheme } from '@hero-design/rn';
|
|
5
|
+
|
|
6
|
+
type StateIndex = 'switchOne' | 'switchTwo' | 'switchThree' | 'switchFour';
|
|
7
|
+
|
|
8
|
+
type SwitchStates = {
|
|
9
|
+
switchOne: boolean;
|
|
10
|
+
switchTwo: boolean;
|
|
11
|
+
switchThree: boolean;
|
|
12
|
+
switchFour: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const SwitchPlayground = () => {
|
|
16
|
+
const theme = useTheme();
|
|
17
|
+
|
|
18
|
+
const [isChecked, setIsChecked] = React.useState<SwitchStates>({
|
|
19
|
+
switchOne: true,
|
|
20
|
+
switchTwo: false,
|
|
21
|
+
switchThree: true,
|
|
22
|
+
switchFour: false,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const toggleState = React.useCallback(
|
|
26
|
+
(switchId: StateIndex) =>
|
|
27
|
+
setIsChecked({
|
|
28
|
+
...isChecked,
|
|
29
|
+
[switchId]: !isChecked[switchId],
|
|
30
|
+
}),
|
|
31
|
+
[isChecked]
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<View
|
|
36
|
+
style={{
|
|
37
|
+
margin: theme.space.medium,
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<Typography.Text style={{ marginVertical: theme.space.xsmall }}>
|
|
41
|
+
Medium size
|
|
42
|
+
</Typography.Text>
|
|
43
|
+
<Switch
|
|
44
|
+
checked={isChecked.switchOne}
|
|
45
|
+
onPress={() => toggleState('switchOne')}
|
|
46
|
+
/>
|
|
47
|
+
<Switch
|
|
48
|
+
style={{ marginTop: theme.space.small }}
|
|
49
|
+
checked={isChecked.switchTwo}
|
|
50
|
+
onPress={() => toggleState('switchTwo')}
|
|
51
|
+
/>
|
|
52
|
+
<Switch checked disabled style={{ marginTop: theme.space.small }} />
|
|
53
|
+
<Switch disabled style={{ marginTop: theme.space.small }} />
|
|
54
|
+
|
|
55
|
+
<Typography.Text style={{ marginVertical: theme.space.xsmall }}>
|
|
56
|
+
Small size
|
|
57
|
+
</Typography.Text>
|
|
58
|
+
<Switch
|
|
59
|
+
size="small"
|
|
60
|
+
checked={isChecked.switchThree}
|
|
61
|
+
onPress={() => toggleState('switchThree')}
|
|
62
|
+
/>
|
|
63
|
+
<Switch
|
|
64
|
+
style={{ marginTop: theme.space.small }}
|
|
65
|
+
size="small"
|
|
66
|
+
checked={isChecked.switchFour}
|
|
67
|
+
onPress={() => toggleState('switchFour')}
|
|
68
|
+
/>
|
|
69
|
+
<Switch
|
|
70
|
+
checked
|
|
71
|
+
disabled
|
|
72
|
+
style={{ marginTop: theme.space.small }}
|
|
73
|
+
size="small"
|
|
74
|
+
/>
|
|
75
|
+
<Switch disabled style={{ marginTop: theme.space.small }} size="small" />
|
|
76
|
+
</View>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default SwitchPlayground;
|
|
@@ -24,7 +24,7 @@ const Header = ({
|
|
|
24
24
|
<StyledHeaderWrapper>
|
|
25
25
|
{typeof content === 'string' ? (
|
|
26
26
|
<StyledHeader adjacentIcon={showCloseButton}>
|
|
27
|
-
<Typography.Text fontSize="
|
|
27
|
+
<Typography.Text fontSize="large" fontWeight="semi-bold">
|
|
28
28
|
{content}
|
|
29
29
|
</Typography.Text>
|
|
30
30
|
</StyledHeader>
|
|
@@ -111,14 +111,14 @@ exports[`BottomSheet renders correctly with close state 1`] = `
|
|
|
111
111
|
Object {
|
|
112
112
|
"color": "#292a2b",
|
|
113
113
|
"fontFamily": "BeVietnamPro-SemiBold",
|
|
114
|
-
"fontSize":
|
|
115
|
-
"letterSpacing": 0.
|
|
116
|
-
"lineHeight":
|
|
114
|
+
"fontSize": 16,
|
|
115
|
+
"letterSpacing": 0.48,
|
|
116
|
+
"lineHeight": 24,
|
|
117
117
|
},
|
|
118
118
|
undefined,
|
|
119
119
|
]
|
|
120
120
|
}
|
|
121
|
-
themeFontSize="
|
|
121
|
+
themeFontSize="large"
|
|
122
122
|
themeFontWeight="semi-bold"
|
|
123
123
|
themeIntent="body"
|
|
124
124
|
>
|
|
@@ -376,14 +376,14 @@ exports[`BottomSheet renders correctly with open state 1`] = `
|
|
|
376
376
|
Object {
|
|
377
377
|
"color": "#292a2b",
|
|
378
378
|
"fontFamily": "BeVietnamPro-SemiBold",
|
|
379
|
-
"fontSize":
|
|
380
|
-
"letterSpacing": 0.
|
|
381
|
-
"lineHeight":
|
|
379
|
+
"fontSize": 16,
|
|
380
|
+
"letterSpacing": 0.48,
|
|
381
|
+
"lineHeight": 24,
|
|
382
382
|
},
|
|
383
383
|
undefined,
|
|
384
384
|
]
|
|
385
385
|
}
|
|
386
|
-
themeFontSize="
|
|
386
|
+
themeFontSize="large"
|
|
387
387
|
themeFontWeight="semi-bold"
|
|
388
388
|
themeIntent="body"
|
|
389
389
|
>
|
|
@@ -40,6 +40,10 @@ interface BottomSheetProps {
|
|
|
40
40
|
* is being dismiss by interacting outside of the bottom sheet.
|
|
41
41
|
*/
|
|
42
42
|
onRequestClose?: () => void;
|
|
43
|
+
/**
|
|
44
|
+
* Callback that is called once the bottom sheet has been dismissed.
|
|
45
|
+
*/
|
|
46
|
+
onDismiss?: () => void;
|
|
43
47
|
/**
|
|
44
48
|
* Displays an X button on bottom sheet header that will invoke onRequestClose callback on press.
|
|
45
49
|
*/
|
|
@@ -69,6 +73,7 @@ const BottomSheet = ({
|
|
|
69
73
|
children,
|
|
70
74
|
onOpen,
|
|
71
75
|
onRequestClose,
|
|
76
|
+
onDismiss,
|
|
72
77
|
showCloseButton = true,
|
|
73
78
|
hasBackdrop = true,
|
|
74
79
|
showDivider = true,
|
|
@@ -93,6 +98,7 @@ const BottomSheet = ({
|
|
|
93
98
|
const endValueOfTransition = open ? 1 : 0;
|
|
94
99
|
if (endValueOfTransition === 0 && value === endValueOfTransition) {
|
|
95
100
|
setVisibility(false);
|
|
101
|
+
onDismiss?.();
|
|
96
102
|
}
|
|
97
103
|
});
|
|
98
104
|
|
|
@@ -2,20 +2,26 @@ import React, { ReactElement } from 'react';
|
|
|
2
2
|
import { StyleProp, View, ViewStyle } from 'react-native';
|
|
3
3
|
import Radio from './Radio';
|
|
4
4
|
import { Spacer } from './StyledRadio';
|
|
5
|
+
import { OptionType } from './types';
|
|
5
6
|
|
|
6
|
-
export interface RadioGroupProps {
|
|
7
|
+
export interface RadioGroupProps<T> {
|
|
7
8
|
/**
|
|
8
9
|
* An array of radio options to be selected.
|
|
9
10
|
*/
|
|
10
|
-
options:
|
|
11
|
+
options: OptionType<T>[];
|
|
11
12
|
/**
|
|
12
13
|
* Radio input value.
|
|
13
14
|
*/
|
|
14
|
-
value:
|
|
15
|
+
value: T;
|
|
15
16
|
/**
|
|
16
17
|
* Press event handler receiving selected radio's value.
|
|
17
18
|
*/
|
|
18
|
-
onPress: (value:
|
|
19
|
+
onPress: (value: T) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Used to extract a unique key for a given option at the specified index. Key is used for caching and as the react key to track item re-ordering.
|
|
22
|
+
* The default extractor checks option.key, and then falls back to using the index, like React does.
|
|
23
|
+
*/
|
|
24
|
+
keyExtractor?: (option: OptionType<T>, index?: number) => string;
|
|
19
25
|
/**
|
|
20
26
|
* Additional style.
|
|
21
27
|
*/
|
|
@@ -26,16 +32,34 @@ export interface RadioGroupProps {
|
|
|
26
32
|
testID?: string;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
function getKey<T>(
|
|
36
|
+
option: OptionType<T>,
|
|
37
|
+
index: number,
|
|
38
|
+
keyExtractor?: (opt: OptionType<T>, i?: number) => string
|
|
39
|
+
) {
|
|
40
|
+
let key: React.Key = '';
|
|
41
|
+
if (keyExtractor !== undefined) {
|
|
42
|
+
key = keyExtractor(option, index);
|
|
43
|
+
} else if (option.key !== undefined) {
|
|
44
|
+
key = option.key;
|
|
45
|
+
} else {
|
|
46
|
+
key = index;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return key;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const RadioGroup = <T,>({
|
|
30
53
|
value,
|
|
31
54
|
onPress,
|
|
32
55
|
options,
|
|
56
|
+
keyExtractor,
|
|
33
57
|
style,
|
|
34
58
|
testID,
|
|
35
|
-
}: RadioGroupProps): ReactElement => (
|
|
59
|
+
}: RadioGroupProps<T>): ReactElement => (
|
|
36
60
|
<View style={style} testID={testID}>
|
|
37
61
|
{options.map((option, index) => (
|
|
38
|
-
<React.Fragment key={option
|
|
62
|
+
<React.Fragment key={getKey(option, index, keyExtractor)}>
|
|
39
63
|
{index !== 0 && <Spacer />}
|
|
40
64
|
<Radio
|
|
41
65
|
text={option.text}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type OptionType<T> = { value: T; text: string; key?: string };
|
|
@@ -2,10 +2,10 @@ import styled from '@emotion/native';
|
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
const StyledHeading = styled(View)(({ theme }) => ({
|
|
5
|
-
paddingVertical: theme.space.
|
|
6
|
-
paddingHorizontal: theme.space.
|
|
7
|
-
backgroundColor: theme.colors.
|
|
8
|
-
marginBottom: theme.space.
|
|
5
|
+
paddingVertical: theme.__hd__.sectionHeading.space.headingVerticalPadding,
|
|
6
|
+
paddingHorizontal: theme.__hd__.sectionHeading.space.headingHorizontalPadding,
|
|
7
|
+
backgroundColor: theme.__hd__.sectionHeading.colors.background,
|
|
8
|
+
marginBottom: theme.__hd__.sectionHeading.space.headingMarginBottom,
|
|
9
9
|
display: 'flex',
|
|
10
10
|
flexDirection: 'row',
|
|
11
11
|
alignContent: 'center',
|
|
@@ -13,7 +13,7 @@ const StyledHeading = styled(View)(({ theme }) => ({
|
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
15
|
const StyledIconWrapper = styled(View)(({ theme }) => ({
|
|
16
|
-
marginRight: theme.space.
|
|
16
|
+
marginRight: theme.__hd__.sectionHeading.space.iconMarginRight,
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
19
|
const StyledWrapper = styled(View)(() => ({
|
package/src/components/SectionHeading/__tests__/{StyledHeading.tsx → StyledHeading.spec.tsx}
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TouchableOpacity } from 'react-native';
|
|
3
|
+
import { FooterText } from './StyledMultiSelect';
|
|
4
|
+
|
|
5
|
+
function Footer({ label, onPress }: { label: string; onPress: () => void }) {
|
|
6
|
+
return (
|
|
7
|
+
<TouchableOpacity onPress={onPress}>
|
|
8
|
+
<FooterText fontSize="large" fontWeight="semi-bold">
|
|
9
|
+
{label}
|
|
10
|
+
</FooterText>
|
|
11
|
+
</TouchableOpacity>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default Footer;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { MultiSelectProps } from '.';
|
|
4
|
+
import Icon from '../../Icon';
|
|
5
|
+
import Typography from '../../Typography';
|
|
6
|
+
import { OptionListWrapper, OptionWrapper, Spacer } from './StyledMultiSelect';
|
|
7
|
+
import { OptionType } from './types';
|
|
8
|
+
|
|
9
|
+
function Option({
|
|
10
|
+
text,
|
|
11
|
+
selected,
|
|
12
|
+
onPress,
|
|
13
|
+
}: {
|
|
14
|
+
text: string;
|
|
15
|
+
selected: boolean;
|
|
16
|
+
onPress: () => void;
|
|
17
|
+
}) {
|
|
18
|
+
return (
|
|
19
|
+
<OptionWrapper themeSelected={selected} onPress={onPress}>
|
|
20
|
+
<View style={{ flex: 1 }}>
|
|
21
|
+
<Typography.Text fontSize="large">{text}</Typography.Text>
|
|
22
|
+
</View>
|
|
23
|
+
{selected && <Icon icon="checkmark" size="small" />}
|
|
24
|
+
</OptionWrapper>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getKey<T>(
|
|
29
|
+
option: OptionType<T>,
|
|
30
|
+
index: number,
|
|
31
|
+
keyExtractor?: (opt: OptionType<T>, i?: number) => string
|
|
32
|
+
) {
|
|
33
|
+
let key: React.Key = '';
|
|
34
|
+
if (keyExtractor !== undefined) {
|
|
35
|
+
key = keyExtractor(option, index);
|
|
36
|
+
} else if (option.key !== undefined) {
|
|
37
|
+
key = option.key;
|
|
38
|
+
} else {
|
|
39
|
+
key = index;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return key;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function OptionList<T>({
|
|
46
|
+
value,
|
|
47
|
+
options,
|
|
48
|
+
onPress,
|
|
49
|
+
keyExtractor,
|
|
50
|
+
}: Pick<
|
|
51
|
+
MultiSelectProps<T>,
|
|
52
|
+
'value' | 'options' | 'onPress' | 'keyExtractor'
|
|
53
|
+
>) {
|
|
54
|
+
return (
|
|
55
|
+
<OptionListWrapper>
|
|
56
|
+
{options.map((opt, index) => (
|
|
57
|
+
<React.Fragment key={getKey(opt, index, keyExtractor)}>
|
|
58
|
+
{index !== 0 && <Spacer />}
|
|
59
|
+
<Option
|
|
60
|
+
text={opt.text}
|
|
61
|
+
selected={value.includes(opt.value)}
|
|
62
|
+
onPress={() => {
|
|
63
|
+
if (value.includes(opt.value)) {
|
|
64
|
+
onPress(value.filter(val => val !== opt.value));
|
|
65
|
+
} else {
|
|
66
|
+
onPress([...value, opt.value]);
|
|
67
|
+
}
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
</React.Fragment>
|
|
71
|
+
))}
|
|
72
|
+
</OptionListWrapper>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default OptionList;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { View, TouchableOpacity } from 'react-native';
|
|
2
|
+
import styled from '@emotion/native';
|
|
3
|
+
import Typography from '../../Typography';
|
|
4
|
+
|
|
5
|
+
const OptionWrapper = styled(TouchableOpacity)<{ themeSelected: boolean }>(
|
|
6
|
+
({ theme, themeSelected }) => ({
|
|
7
|
+
flexDirection: 'row',
|
|
8
|
+
justifyContent: 'space-between',
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
borderRadius: theme.__hd__.select.radii.option,
|
|
11
|
+
padding: theme.__hd__.select.space.optionPadding,
|
|
12
|
+
backgroundColor: themeSelected
|
|
13
|
+
? theme.__hd__.select.colors.checkedOption
|
|
14
|
+
: theme.__hd__.select.colors.option,
|
|
15
|
+
})
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const OptionListWrapper = styled(View)(({ theme }) => ({
|
|
19
|
+
padding: theme.__hd__.select.space.optionListPadding,
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const Spacer = styled(View)(({ theme }) => ({
|
|
23
|
+
marginTop: theme.__hd__.select.space.optionListSpacing,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const FooterText = styled(Typography.Text)(({ theme }) => ({
|
|
27
|
+
color: theme.__hd__.select.colors.footerText,
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
export { OptionWrapper, OptionListWrapper, Spacer, FooterText };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderWithTheme from '../../../../testHelpers/renderWithTheme';
|
|
3
|
+
import {
|
|
4
|
+
OptionWrapper,
|
|
5
|
+
OptionListWrapper,
|
|
6
|
+
Spacer,
|
|
7
|
+
FooterText,
|
|
8
|
+
} from '../StyledMultiSelect';
|
|
9
|
+
|
|
10
|
+
describe('OptionWrapper', () => {
|
|
11
|
+
it.each`
|
|
12
|
+
themeSelected
|
|
13
|
+
${true}
|
|
14
|
+
${false}
|
|
15
|
+
`('has selected style: $themeSelected', ({ themeSelected }) => {
|
|
16
|
+
const { toJSON } = renderWithTheme(
|
|
17
|
+
<OptionWrapper themeSelected={themeSelected} />
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
expect(toJSON()).toMatchSnapshot();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('OptionListWrapper', () => {
|
|
25
|
+
it('has correct style', () => {
|
|
26
|
+
const { toJSON } = renderWithTheme(<OptionListWrapper />);
|
|
27
|
+
|
|
28
|
+
expect(toJSON()).toMatchSnapshot();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('Spacer', () => {
|
|
33
|
+
it('has correct style', () => {
|
|
34
|
+
const { toJSON } = renderWithTheme(<Spacer />);
|
|
35
|
+
|
|
36
|
+
expect(toJSON()).toMatchSnapshot();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('FooterText', () => {
|
|
41
|
+
it('has correct style', () => {
|
|
42
|
+
const { toJSON, getByText } = renderWithTheme(
|
|
43
|
+
<FooterText>Confirm</FooterText>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(getByText('Confirm')).toBeDefined();
|
|
47
|
+
expect(toJSON()).toMatchSnapshot();
|
|
48
|
+
});
|
|
49
|
+
});
|
package/src/components/Select/MultiSelect/__tests__/__snapshots__/StyledMultiSelect.spec.tsx.snap
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`FooterText has correct style 1`] = `
|
|
4
|
+
<Text
|
|
5
|
+
style={
|
|
6
|
+
Array [
|
|
7
|
+
Object {
|
|
8
|
+
"color": "#292a2b",
|
|
9
|
+
"fontFamily": "BeVietnamPro-Regular",
|
|
10
|
+
"fontSize": 14,
|
|
11
|
+
"letterSpacing": 0.42,
|
|
12
|
+
"lineHeight": 22,
|
|
13
|
+
},
|
|
14
|
+
Array [
|
|
15
|
+
Object {
|
|
16
|
+
"color": "#7622d7",
|
|
17
|
+
},
|
|
18
|
+
undefined,
|
|
19
|
+
],
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
themeFontSize="medium"
|
|
23
|
+
themeFontWeight="regular"
|
|
24
|
+
themeIntent="body"
|
|
25
|
+
>
|
|
26
|
+
Confirm
|
|
27
|
+
</Text>
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
exports[`OptionListWrapper has correct style 1`] = `
|
|
31
|
+
<View
|
|
32
|
+
style={
|
|
33
|
+
Array [
|
|
34
|
+
Object {
|
|
35
|
+
"padding": 16,
|
|
36
|
+
},
|
|
37
|
+
undefined,
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
exports[`OptionWrapper has selected style: false 1`] = `
|
|
44
|
+
<View
|
|
45
|
+
accessible={true}
|
|
46
|
+
collapsable={false}
|
|
47
|
+
focusable={false}
|
|
48
|
+
nativeID="animatedComponent"
|
|
49
|
+
onClick={[Function]}
|
|
50
|
+
onResponderGrant={[Function]}
|
|
51
|
+
onResponderMove={[Function]}
|
|
52
|
+
onResponderRelease={[Function]}
|
|
53
|
+
onResponderTerminate={[Function]}
|
|
54
|
+
onResponderTerminationRequest={[Function]}
|
|
55
|
+
onStartShouldSetResponder={[Function]}
|
|
56
|
+
style={
|
|
57
|
+
Object {
|
|
58
|
+
"alignItems": "center",
|
|
59
|
+
"backgroundColor": "#ffffff",
|
|
60
|
+
"borderRadius": 4,
|
|
61
|
+
"flexDirection": "row",
|
|
62
|
+
"justifyContent": "space-between",
|
|
63
|
+
"opacity": 1,
|
|
64
|
+
"padding": 16,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/>
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
exports[`OptionWrapper has selected style: true 1`] = `
|
|
71
|
+
<View
|
|
72
|
+
accessible={true}
|
|
73
|
+
collapsable={false}
|
|
74
|
+
focusable={false}
|
|
75
|
+
nativeID="animatedComponent"
|
|
76
|
+
onClick={[Function]}
|
|
77
|
+
onResponderGrant={[Function]}
|
|
78
|
+
onResponderMove={[Function]}
|
|
79
|
+
onResponderRelease={[Function]}
|
|
80
|
+
onResponderTerminate={[Function]}
|
|
81
|
+
onResponderTerminationRequest={[Function]}
|
|
82
|
+
onStartShouldSetResponder={[Function]}
|
|
83
|
+
style={
|
|
84
|
+
Object {
|
|
85
|
+
"alignItems": "center",
|
|
86
|
+
"backgroundColor": "#f1e9fb",
|
|
87
|
+
"borderRadius": 4,
|
|
88
|
+
"flexDirection": "row",
|
|
89
|
+
"justifyContent": "space-between",
|
|
90
|
+
"opacity": 1,
|
|
91
|
+
"padding": 16,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/>
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
exports[`Spacer has correct style 1`] = `
|
|
98
|
+
<View
|
|
99
|
+
style={
|
|
100
|
+
Array [
|
|
101
|
+
Object {
|
|
102
|
+
"marginTop": 4,
|
|
103
|
+
},
|
|
104
|
+
undefined,
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
/>
|
|
108
|
+
`;
|