@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.
Files changed (74) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/es/index.js +474 -110
  3. package/lib/index.js +474 -108
  4. package/package.json +2 -2
  5. package/playground/.turbo/turbo-type-check.log +7 -0
  6. package/playground/package.json +3 -3
  7. package/playground/src/App.tsx +6 -0
  8. package/playground/src/ContentNavigator.tsx +3 -10
  9. package/playground/src/Select.tsx +32 -0
  10. package/playground/src/Switch.tsx +80 -0
  11. package/src/components/BottomSheet/Header.tsx +1 -1
  12. package/src/components/BottomSheet/__tests__/__snapshots__/index.spec.tsx.snap +8 -8
  13. package/src/components/BottomSheet/index.tsx +6 -0
  14. package/src/components/Radio/RadioGroup.tsx +31 -7
  15. package/src/components/Radio/types.ts +1 -0
  16. package/src/components/SectionHeading/StyledHeading.tsx +5 -5
  17. package/src/components/SectionHeading/__tests__/{StyledHeading.tsx → StyledHeading.spec.tsx} +0 -0
  18. package/src/components/SectionHeading/__tests__/__snapshots__/{StyledHeading.tsx.snap → StyledHeading.spec.tsx.snap} +0 -0
  19. package/src/components/Select/MultiSelect/Footer.tsx +15 -0
  20. package/src/components/Select/MultiSelect/OptionList.tsx +76 -0
  21. package/src/components/Select/MultiSelect/StyledMultiSelect.tsx +30 -0
  22. package/src/components/Select/MultiSelect/__tests__/StyledMultiSelect.spec.tsx +49 -0
  23. package/src/components/Select/MultiSelect/__tests__/__snapshots__/StyledMultiSelect.spec.tsx.snap +108 -0
  24. package/src/components/Select/MultiSelect/__tests__/__snapshots__/index.spec.tsx.snap +1630 -0
  25. package/src/components/Select/MultiSelect/__tests__/index.spec.tsx +94 -0
  26. package/src/components/Select/MultiSelect/index.tsx +103 -0
  27. package/src/components/Select/MultiSelect/types.ts +1 -0
  28. package/src/components/Select/index.tsx +5 -0
  29. package/src/components/Switch/StyledSwitch.tsx +50 -0
  30. package/src/components/Switch/__tests__/StyledHeading.spec.tsx +42 -0
  31. package/src/components/Switch/__tests__/__snapshots__/StyledHeading.spec.tsx.snap +74 -0
  32. package/src/components/Switch/__tests__/__snapshots__/index.spec.tsx.snap +129 -0
  33. package/src/components/Switch/__tests__/index.spec.tsx +24 -0
  34. package/src/components/Switch/index.tsx +87 -0
  35. package/src/components/TextInput/StyledTextInput.tsx +2 -6
  36. package/src/components/TextInput/__tests__/StyledTextInput.spec.tsx +1 -7
  37. package/src/components/TextInput/__tests__/__snapshots__/StyledTextInput.spec.tsx.snap +1 -22
  38. package/src/components/TextInput/__tests__/index.spec.tsx +2 -1
  39. package/src/components/TextInput/index.tsx +19 -6
  40. package/src/index.ts +4 -0
  41. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +58 -1
  42. package/src/theme/components/sectionHeading.ts +18 -0
  43. package/src/theme/components/select.ts +23 -0
  44. package/src/theme/components/switch.ts +50 -0
  45. package/src/theme/components/textInput.ts +1 -1
  46. package/src/theme/global/colors.ts +1 -0
  47. package/src/theme/index.ts +12 -3
  48. package/types/components/BottomSheet/index.d.ts +5 -1
  49. package/types/components/Radio/RadioGroup.d.ts +11 -8
  50. package/types/components/Radio/index.d.ts +1 -1
  51. package/types/components/Radio/types.d.ts +5 -0
  52. package/types/components/SectionHeading/__tests__/{StyledHeading.d.ts → StyledHeading.spec.d.ts} +0 -0
  53. package/types/components/Select/MultiSelect/Footer.d.ts +5 -0
  54. package/types/components/Select/MultiSelect/OptionList.d.ts +3 -0
  55. package/types/components/Select/MultiSelect/StyledMultiSelect.d.ts +26 -0
  56. package/types/components/Select/MultiSelect/__tests__/StyledMultiSelect.spec.d.ts +1 -0
  57. package/types/components/Select/MultiSelect/__tests__/index.spec.d.ts +1 -0
  58. package/types/components/Select/MultiSelect/index.d.ts +39 -0
  59. package/types/components/Select/MultiSelect/types.d.ts +5 -0
  60. package/types/components/Select/index.d.ts +5 -0
  61. package/types/components/Switch/StyledSwitch.d.ts +36 -0
  62. package/types/components/Switch/__tests__/StyledHeading.spec.d.ts +1 -0
  63. package/types/components/Switch/__tests__/index.spec.d.ts +1 -0
  64. package/types/components/Switch/index.d.ts +30 -0
  65. package/types/components/TextInput/StyledTextInput.d.ts +1 -5
  66. package/types/components/TextInput/index.d.ts +13 -5
  67. package/types/index.d.ts +3 -1
  68. package/types/theme/components/sectionHeading.d.ts +13 -0
  69. package/types/theme/components/select.d.ts +17 -0
  70. package/types/theme/components/switch.d.ts +32 -0
  71. package/types/theme/components/textInput.d.ts +1 -1
  72. package/types/theme/global/colors.d.ts +1 -0
  73. package/types/theme/global/index.d.ts +1 -0
  74. package/types/theme/index.d.ts +8 -2
@@ -0,0 +1,94 @@
1
+ import { fireEvent } from '@testing-library/react-native';
2
+ import React from 'react';
3
+ import renderWithTheme from '../../../../testHelpers/renderWithTheme';
4
+ import MultiSelect from '..';
5
+
6
+ const options = [
7
+ { text: 'Monday', value: 'mon' },
8
+ { text: 'Tuesday', value: 'tue' },
9
+ { text: 'Wednesday', value: 'wed' },
10
+ { text: 'Thursday', value: 'thu' },
11
+ { text: 'Friday', value: 'fri' },
12
+ { text: 'Saturday', value: 'sat' },
13
+ { text: 'Sunday', value: 'sun' },
14
+ ];
15
+
16
+ describe('rendering', () => {
17
+ it('renders correctly when bottom sheet is NOT visible', () => {
18
+ const { queryAllByText, toJSON, getByTestId } = renderWithTheme(
19
+ <MultiSelect
20
+ label="Allow notifications"
21
+ footerLabel="Confirm"
22
+ options={options}
23
+ value={['mon', 'tue']}
24
+ onPress={jest.fn()}
25
+ />
26
+ );
27
+
28
+ expect(toJSON()).toMatchSnapshot();
29
+ expect(queryAllByText('Allow notifications')).toHaveLength(2);
30
+ expect(getByTestId('text-input').props.value).toBe('Monday, Tuesday');
31
+ });
32
+
33
+ it('renders correctly when bottom sheet is visible', () => {
34
+ const { queryAllByText, getByText, toJSON, getByTestId } = renderWithTheme(
35
+ <MultiSelect
36
+ label="Allow notifications"
37
+ footerLabel="Confirm"
38
+ options={options}
39
+ value={['mon', 'tue']}
40
+ onPress={jest.fn()}
41
+ />
42
+ );
43
+ fireEvent.press(getByTestId('text-input'));
44
+
45
+ expect(toJSON()).toMatchSnapshot();
46
+ expect(queryAllByText('Allow notifications')).toHaveLength(2);
47
+ expect(getByText('Monday')).toBeDefined();
48
+ expect(getByText('Tuesday')).toBeDefined();
49
+ expect(getByText('Wednesday')).toBeDefined();
50
+ expect(getByText('Thursday')).toBeDefined();
51
+ expect(getByText('Friday')).toBeDefined();
52
+ expect(getByText('Saturday')).toBeDefined();
53
+ expect(getByText('Sunday')).toBeDefined();
54
+ expect(getByText('Confirm')).toBeDefined();
55
+ });
56
+ });
57
+
58
+ describe('behavior', () => {
59
+ it('calls onPress when pressing footer of bottom sheet', () => {
60
+ const onPress = jest.fn();
61
+ const { getByText, getByTestId } = renderWithTheme(
62
+ <MultiSelect
63
+ label="Allow notifications"
64
+ footerLabel="Confirm"
65
+ options={options}
66
+ value={['mon', 'tue']}
67
+ onPress={onPress}
68
+ testID="multi-select"
69
+ />
70
+ );
71
+ fireEvent.press(getByTestId('multi-select'));
72
+ fireEvent.press(getByText('Confirm'));
73
+
74
+ expect(onPress).toBeCalledTimes(1);
75
+ });
76
+
77
+ it('does NOT call onPress when pressing closing button of bottom sheet', () => {
78
+ const onPress = jest.fn();
79
+ const { getByTestId } = renderWithTheme(
80
+ <MultiSelect
81
+ label="Allow notifications"
82
+ footerLabel="Confirm"
83
+ options={options}
84
+ value={['mon', 'tue']}
85
+ onPress={onPress}
86
+ testID="multi-select"
87
+ />
88
+ );
89
+ fireEvent.press(getByTestId('multi-select'));
90
+ fireEvent.press(getByTestId('bottom-sheet-close-icon'));
91
+
92
+ expect(onPress).toBeCalledTimes(0);
93
+ });
94
+ });
@@ -0,0 +1,103 @@
1
+ import { useTheme } from '@emotion/react';
2
+ import React, { useState } from 'react';
3
+ import { StyleProp, ViewStyle, TouchableOpacity } from 'react-native';
4
+ import BottomSheet from '../../BottomSheet';
5
+ import TextInput from '../../TextInput';
6
+ import Footer from './Footer';
7
+ import OptionList from './OptionList';
8
+ import { OptionType } from './types';
9
+
10
+ export interface MultiSelectProps<T> {
11
+ /**
12
+ * An array of options to be selected.
13
+ */
14
+ options: OptionType<T>[];
15
+ /**
16
+ * Current selected value.
17
+ */
18
+ value: T[];
19
+ /**
20
+ * onPress event handler.
21
+ */
22
+ onPress: (value: T[]) => void;
23
+ /**
24
+ * Field label.
25
+ */
26
+ label: string;
27
+ /**
28
+ * Footer label.
29
+ */
30
+ footerLabel: string;
31
+ /**
32
+ * 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.
33
+ * The default extractor checks option.key, and then falls back to using the index, like React does.
34
+ */
35
+ keyExtractor?: (option: OptionType<T>, index?: number) => string;
36
+ /**
37
+ * Additional style.
38
+ */
39
+ style?: StyleProp<ViewStyle>;
40
+ /**
41
+ * Testing id of the component.
42
+ */
43
+ testID?: string;
44
+ }
45
+
46
+ function MultiSelect<T>({
47
+ options,
48
+ value,
49
+ testID,
50
+ style,
51
+ label,
52
+ footerLabel,
53
+ onPress,
54
+ }: MultiSelectProps<T>) {
55
+ const theme = useTheme();
56
+ const [open, setOpen] = useState(false);
57
+ const [selectingValue, setSelectingValue] = useState(value);
58
+ const displayedValue = options
59
+ .filter(opt => value.includes(opt.value))
60
+ .map(opt => opt.text)
61
+ .join(', ');
62
+
63
+ return (
64
+ <TouchableOpacity onPress={() => setOpen(true)}>
65
+ <TextInput
66
+ label={label}
67
+ value={displayedValue}
68
+ onPressIn={() => setOpen(true)}
69
+ editable={false}
70
+ // when input is not editable on Android, the text color is gray
71
+ // hence, adding this to make the text color the same as iOS
72
+ textStyle={{ color: theme.colors.text }}
73
+ suffix="arrow-down"
74
+ multiline
75
+ style={style}
76
+ testID={testID}
77
+ />
78
+ <BottomSheet
79
+ open={open}
80
+ onRequestClose={() => setOpen(false)}
81
+ onDismiss={() => setSelectingValue(value)}
82
+ header={label}
83
+ footer={
84
+ <Footer
85
+ label={footerLabel}
86
+ onPress={() => {
87
+ setOpen(false);
88
+ onPress(selectingValue);
89
+ }}
90
+ />
91
+ }
92
+ >
93
+ <OptionList
94
+ options={options}
95
+ value={selectingValue}
96
+ onPress={setSelectingValue}
97
+ />
98
+ </BottomSheet>
99
+ </TouchableOpacity>
100
+ );
101
+ }
102
+
103
+ export default MultiSelect;
@@ -0,0 +1 @@
1
+ export type OptionType<T> = { value: T; text: string; key?: string };
@@ -0,0 +1,5 @@
1
+ import MultiSelect from './MultiSelect';
2
+
3
+ const CompoundSelect = { Multi: MultiSelect } as const;
4
+
5
+ export default CompoundSelect;
@@ -0,0 +1,50 @@
1
+ import styled from '@emotion/native';
2
+ import { Animated, View } from 'react-native';
3
+
4
+ type ThemeSize = 'small' | 'medium';
5
+
6
+ const StyledWrapper = styled(View)<{
7
+ themeChecked: boolean | undefined;
8
+ themeSize: ThemeSize;
9
+ }>(({ theme, themeChecked, themeSize }) => ({
10
+ height: theme.__hd__.switch.heights[themeSize],
11
+ width: theme.__hd__.switch.widths[themeSize],
12
+ paddingHorizontal: theme.__hd__.switch.spaces[themeSize],
13
+ borderRadius: theme.__hd__.switch.radii.rounded,
14
+ backgroundColor: themeChecked
15
+ ? theme.__hd__.switch.colors.active
16
+ : theme.__hd__.switch.colors.inactive,
17
+ }));
18
+
19
+ const StyledDisabledWrapper = styled(View)<{
20
+ themeSize: ThemeSize;
21
+ }>(({ theme, themeSize }) => ({
22
+ position: 'absolute',
23
+ height: theme.__hd__.switch.heights[themeSize],
24
+ width: theme.__hd__.switch.widths[themeSize],
25
+ borderRadius: theme.__hd__.switch.radii.rounded,
26
+ backgroundColor: theme.__hd__.switch.colors.thumb,
27
+ zIndex: 9999,
28
+ opacity: 0.8,
29
+ }));
30
+
31
+ const StyledThumbWrapper = styled(View)<{
32
+ themeSize: ThemeSize;
33
+ }>(({ theme, themeSize }) => ({
34
+ height: theme.__hd__.switch.heights[themeSize],
35
+ width: theme.__hd__.switch.widths[themeSize],
36
+ borderRadius: theme.__hd__.switch.radii.rounded,
37
+ display: 'flex',
38
+ justifyContent: 'center',
39
+ }));
40
+
41
+ const StyledKnot = styled(Animated.View)<{
42
+ themeSize: ThemeSize;
43
+ }>(({ theme, themeSize }) => ({
44
+ width: theme.__hd__.switch.thumbSizes[themeSize],
45
+ height: theme.__hd__.switch.thumbSizes[themeSize],
46
+ backgroundColor: theme.__hd__.switch.colors.thumb,
47
+ borderRadius: theme.__hd__.switch.radii.rounded,
48
+ }));
49
+
50
+ export { StyledWrapper, StyledDisabledWrapper, StyledThumbWrapper, StyledKnot };
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../testHelpers/renderWithTheme';
3
+ import {
4
+ StyledWrapper,
5
+ StyledDisabledWrapper,
6
+ StyledThumbWrapper,
7
+ StyledKnot,
8
+ } from '../StyledSwitch';
9
+
10
+ describe('StyledWrapper', () => {
11
+ it('renders correct style', () => {
12
+ const { toJSON } = renderWithTheme(
13
+ <StyledWrapper themeChecked themeSize="medium" />
14
+ );
15
+ expect(toJSON()).toMatchSnapshot();
16
+ });
17
+ });
18
+
19
+ describe('StyledDisabledWrapper', () => {
20
+ it('renders correct style', () => {
21
+ const { toJSON } = renderWithTheme(
22
+ <StyledDisabledWrapper themeSize="medium" />
23
+ );
24
+ expect(toJSON()).toMatchSnapshot();
25
+ });
26
+ });
27
+
28
+ describe('StyledThumbWrapper', () => {
29
+ it('renders correct style', () => {
30
+ const { toJSON } = renderWithTheme(
31
+ <StyledThumbWrapper themeSize="medium" />
32
+ );
33
+ expect(toJSON()).toMatchSnapshot();
34
+ });
35
+ });
36
+
37
+ describe('StyledKnot', () => {
38
+ it('renders correct style', () => {
39
+ const { toJSON } = renderWithTheme(<StyledKnot themeSize="medium" />);
40
+ expect(toJSON()).toMatchSnapshot();
41
+ });
42
+ });
@@ -0,0 +1,74 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`StyledDisabledWrapper renders correct style 1`] = `
4
+ <View
5
+ style={
6
+ Array [
7
+ Object {
8
+ "backgroundColor": "#ffffff",
9
+ "borderRadius": 999,
10
+ "height": 28.799999999999997,
11
+ "opacity": 0.8,
12
+ "position": "absolute",
13
+ "width": 56,
14
+ "zIndex": 9999,
15
+ },
16
+ undefined,
17
+ ]
18
+ }
19
+ themeSize="medium"
20
+ />
21
+ `;
22
+
23
+ exports[`StyledKnot renders correct style 1`] = `
24
+ <View
25
+ collapsable={false}
26
+ nativeID="animatedComponent"
27
+ style={
28
+ Object {
29
+ "backgroundColor": "#ffffff",
30
+ "borderRadius": 999,
31
+ "height": 20.8,
32
+ "width": 20.8,
33
+ }
34
+ }
35
+ themeSize="medium"
36
+ />
37
+ `;
38
+
39
+ exports[`StyledThumbWrapper renders correct style 1`] = `
40
+ <View
41
+ style={
42
+ Array [
43
+ Object {
44
+ "borderRadius": 999,
45
+ "display": "flex",
46
+ "height": 28.799999999999997,
47
+ "justifyContent": "center",
48
+ "width": 56,
49
+ },
50
+ undefined,
51
+ ]
52
+ }
53
+ themeSize="medium"
54
+ />
55
+ `;
56
+
57
+ exports[`StyledWrapper renders correct style 1`] = `
58
+ <View
59
+ style={
60
+ Array [
61
+ Object {
62
+ "backgroundColor": "#7622d7",
63
+ "borderRadius": 999,
64
+ "height": 28.799999999999997,
65
+ "paddingHorizontal": 4,
66
+ "width": 56,
67
+ },
68
+ undefined,
69
+ ]
70
+ }
71
+ themeChecked={true}
72
+ themeSize="medium"
73
+ />
74
+ `;
@@ -0,0 +1,129 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Switch renders correctly 1`] = `
4
+ <View
5
+ accessibilityState={
6
+ Object {
7
+ "disabled": false,
8
+ }
9
+ }
10
+ accessible={true}
11
+ focusable={false}
12
+ onClick={[Function]}
13
+ onResponderGrant={[Function]}
14
+ onResponderMove={[Function]}
15
+ onResponderRelease={[Function]}
16
+ onResponderTerminate={[Function]}
17
+ onResponderTerminationRequest={[Function]}
18
+ onStartShouldSetResponder={[Function]}
19
+ style={
20
+ Array [
21
+ Object {
22
+ "backgroundColor": "#727478",
23
+ "borderRadius": 999,
24
+ "height": 28.799999999999997,
25
+ "paddingHorizontal": 4,
26
+ "width": 56,
27
+ },
28
+ undefined,
29
+ ]
30
+ }
31
+ testID="switch"
32
+ themeSize="medium"
33
+ >
34
+ <View
35
+ style={
36
+ Array [
37
+ Object {
38
+ "borderRadius": 999,
39
+ "display": "flex",
40
+ "height": 28.799999999999997,
41
+ "justifyContent": "center",
42
+ "width": 56,
43
+ },
44
+ undefined,
45
+ ]
46
+ }
47
+ themeSize="medium"
48
+ >
49
+ <View
50
+ collapsable={false}
51
+ nativeID="animatedComponent"
52
+ style={
53
+ Object {
54
+ "backgroundColor": "#ffffff",
55
+ "borderRadius": 999,
56
+ "height": 20.8,
57
+ "left": 0,
58
+ "width": 20.8,
59
+ }
60
+ }
61
+ themeSize="medium"
62
+ />
63
+ </View>
64
+ </View>
65
+ `;
66
+
67
+ exports[`Switch trigger press function correctly 1`] = `
68
+ <View
69
+ accessibilityState={
70
+ Object {
71
+ "disabled": false,
72
+ }
73
+ }
74
+ accessible={true}
75
+ focusable={true}
76
+ onClick={[Function]}
77
+ onResponderGrant={[Function]}
78
+ onResponderMove={[Function]}
79
+ onResponderRelease={[Function]}
80
+ onResponderTerminate={[Function]}
81
+ onResponderTerminationRequest={[Function]}
82
+ onStartShouldSetResponder={[Function]}
83
+ style={
84
+ Array [
85
+ Object {
86
+ "backgroundColor": "#727478",
87
+ "borderRadius": 999,
88
+ "height": 28.799999999999997,
89
+ "paddingHorizontal": 4,
90
+ "width": 56,
91
+ },
92
+ undefined,
93
+ ]
94
+ }
95
+ testID="switch"
96
+ themeSize="medium"
97
+ >
98
+ <View
99
+ style={
100
+ Array [
101
+ Object {
102
+ "borderRadius": 999,
103
+ "display": "flex",
104
+ "height": 28.799999999999997,
105
+ "justifyContent": "center",
106
+ "width": 56,
107
+ },
108
+ undefined,
109
+ ]
110
+ }
111
+ themeSize="medium"
112
+ >
113
+ <View
114
+ collapsable={false}
115
+ nativeID="animatedComponent"
116
+ style={
117
+ Object {
118
+ "backgroundColor": "#ffffff",
119
+ "borderRadius": 999,
120
+ "height": 20.8,
121
+ "left": 0,
122
+ "width": 20.8,
123
+ }
124
+ }
125
+ themeSize="medium"
126
+ />
127
+ </View>
128
+ </View>
129
+ `;
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { fireEvent } from '@testing-library/react-native';
3
+
4
+ import renderWithTheme from '../../../testHelpers/renderWithTheme';
5
+ import Switch from '..';
6
+
7
+ describe('Switch', () => {
8
+ it('renders correctly', () => {
9
+ const wrapper = renderWithTheme(<Switch testID="switch" />);
10
+ expect(wrapper.queryAllByTestId('switch')).toHaveLength(1);
11
+ expect(wrapper.toJSON()).toMatchSnapshot();
12
+ });
13
+
14
+ it('trigger press function correctly', () => {
15
+ const pressFn = jest.fn();
16
+ const wrapper = renderWithTheme(
17
+ <Switch testID="switch" onPress={pressFn} />
18
+ );
19
+ fireEvent.press(wrapper.getByTestId('switch'));
20
+
21
+ expect(wrapper.toJSON()).toMatchSnapshot();
22
+ expect(pressFn).toBeCalled();
23
+ });
24
+ });
@@ -0,0 +1,87 @@
1
+ import { useTheme } from '@emotion/react';
2
+ import React, { ReactElement, useState, useEffect } from 'react';
3
+
4
+ import {
5
+ StyleProp,
6
+ ViewStyle,
7
+ Animated,
8
+ Easing,
9
+ TouchableWithoutFeedback,
10
+ } from 'react-native';
11
+
12
+ import {
13
+ StyledDisabledWrapper,
14
+ StyledKnot,
15
+ StyledThumbWrapper,
16
+ StyledWrapper,
17
+ } from './StyledSwitch';
18
+
19
+ export interface SwitchProps {
20
+ /**
21
+ * Control whether the switch is checked
22
+ */
23
+ checked?: boolean;
24
+ /**
25
+ * Whether the switch is disabled
26
+ */
27
+ disabled?: boolean;
28
+ /**
29
+ * Event handler.
30
+ */
31
+ onPress?: () => void;
32
+ /**
33
+ * Size of the switch
34
+ */
35
+ size?: 'small' | 'medium';
36
+ /**
37
+ * Addditional style.
38
+ */
39
+ style?: StyleProp<ViewStyle>;
40
+ /**
41
+ * Testing id of the component.
42
+ */
43
+ testID?: string;
44
+ }
45
+
46
+ const Switch = ({
47
+ size = 'medium',
48
+ disabled = false,
49
+ checked,
50
+ onPress,
51
+ style,
52
+ testID,
53
+ }: SwitchProps): ReactElement => {
54
+ const theme = useTheme();
55
+
56
+ const offset = checked
57
+ ? theme.__hd__.switch.widths[size] -
58
+ theme.__hd__.switch.thumbSizes[size] -
59
+ theme.__hd__.switch.spaces[size] * 2
60
+ : theme.__hd__.switch.spaces.inactive;
61
+
62
+ const [animatedOffset] = useState(() => new Animated.Value(offset));
63
+
64
+ useEffect(() => {
65
+ Animated.timing(animatedOffset, {
66
+ toValue: offset,
67
+ easing: Easing.inOut(Easing.cubic),
68
+ useNativeDriver: false,
69
+ }).start();
70
+ }, [checked]);
71
+ return (
72
+ <TouchableWithoutFeedback
73
+ testID={testID}
74
+ onPress={onPress}
75
+ disabled={disabled}
76
+ >
77
+ <StyledWrapper themeChecked={checked} themeSize={size} style={style}>
78
+ {disabled && <StyledDisabledWrapper themeSize={size} />}
79
+ <StyledThumbWrapper themeSize={size}>
80
+ <StyledKnot themeSize={size} style={{ left: animatedOffset }} />
81
+ </StyledThumbWrapper>
82
+ </StyledWrapper>
83
+ </TouchableWithoutFeedback>
84
+ );
85
+ };
86
+
87
+ export default Switch;
@@ -1,7 +1,6 @@
1
1
  import { TextInput, View } from 'react-native';
2
2
  import styled from '@emotion/native';
3
3
  import Typography from '../Typography';
4
- import Icon from '../Icon';
5
4
 
6
5
  const Container = styled(View)(({ theme }) => ({
7
6
  position: 'relative',
@@ -22,13 +21,10 @@ const Label = styled(Typography.Text)(({ theme }) => ({
22
21
  paddingHorizontal: theme.__hd__.textInput.space.labelHorizontalPadding,
23
22
  }));
24
23
 
25
- const Prefix = styled(Icon)(({ theme }) => ({
26
- marginRight: theme.__hd__.textInput.space.prefixMarginRight,
27
- }));
28
-
29
24
  const StyledTextInput = styled(TextInput)(({ theme }) => ({
30
25
  flex: 1,
31
26
  fontSize: theme.__hd__.textInput.fontSizes.text,
27
+ marginHorizontal: theme.__hd__.textInput.space.inputHorizontalMargin,
32
28
  }));
33
29
 
34
- export { Container, Label, Prefix, StyledTextInput };
30
+ export { Container, Label, StyledTextInput };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import renderWithTheme from '../../../testHelpers/renderWithTheme';
3
- import { Container, Label, Prefix, StyledTextInput } from '../StyledTextInput';
3
+ import { Container, Label, StyledTextInput } from '../StyledTextInput';
4
4
 
5
5
  describe('Container', () => {
6
6
  it('renders correctly', () => {
@@ -17,13 +17,7 @@ describe('Label', () => {
17
17
  expect(toJSON()).toMatchSnapshot();
18
18
  });
19
19
  });
20
- describe('Prefix', () => {
21
- it('renders correctly', () => {
22
- const { toJSON } = renderWithTheme(<Prefix icon="user" />);
23
20
 
24
- expect(toJSON()).toMatchSnapshot();
25
- });
26
- });
27
21
  describe('StyledTextInput', () => {
28
22
  it('renders correctly', () => {
29
23
  const { toJSON } = renderWithTheme(<StyledTextInput />);
@@ -51,28 +51,6 @@ exports[`Label renders correctly 1`] = `
51
51
  </Text>
52
52
  `;
53
53
 
54
- exports[`Prefix renders correctly 1`] = `
55
- <HeroIcon
56
- name="user"
57
- style={
58
- Array [
59
- Object {
60
- "color": "#292a2b",
61
- "fontSize": 24,
62
- },
63
- Array [
64
- Object {
65
- "marginRight": 8,
66
- },
67
- undefined,
68
- ],
69
- ]
70
- }
71
- themeIntent="text"
72
- themeSize="medium"
73
- />
74
- `;
75
-
76
54
  exports[`StyledTextInput renders correctly 1`] = `
77
55
  <TextInput
78
56
  style={
@@ -80,6 +58,7 @@ exports[`StyledTextInput renders correctly 1`] = `
80
58
  Object {
81
59
  "flex": 1,
82
60
  "fontSize": 16,
61
+ "marginHorizontal": 8,
83
62
  },
84
63
  undefined,
85
64
  ]