Skip to content

Commit 6fdb606

Browse files
committed
feat: implement switch component
1 parent 9c8453a commit 6fdb606

File tree

9 files changed

+423
-32
lines changed

9 files changed

+423
-32
lines changed

example/.ondevice/storybook.requires.js

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,57 @@ import {
66
addParameters,
77
addArgsEnhancer,
88
clearDecorators,
9-
} from '@storybook/react-native'
9+
} from "@storybook/react-native";
1010

1111
global.STORIES = [
1212
{
13-
titlePrefix: '',
14-
directory: './src',
15-
files: '**/*.stories.?(ts|tsx|js|jsx)',
13+
titlePrefix: "",
14+
directory: "./src",
15+
files: "**/*.stories.?(ts|tsx|js|jsx)",
1616
importPathMatcher:
17-
'^\\.[\\\\/](?:src(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)\\/|\\/|$)(?!\\.)(?=.)[^/]*?\\.stories\\.(?:ts|tsx|js|jsx)?)$',
17+
"^\\.[\\\\/](?:src(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)\\/|\\/|$)(?!\\.)(?=.)[^/]*?\\.stories\\.(?:ts|tsx|js|jsx)?)$",
1818
},
19-
]
19+
];
2020

21-
import '@storybook/addon-ondevice-notes/register'
22-
import '@storybook/addon-ondevice-controls/register'
23-
import '@storybook/addon-ondevice-backgrounds/register'
24-
import '@storybook/addon-ondevice-actions/register'
21+
import "@storybook/addon-ondevice-notes/register";
22+
import "@storybook/addon-ondevice-controls/register";
23+
import "@storybook/addon-ondevice-backgrounds/register";
24+
import "@storybook/addon-ondevice-actions/register";
2525

26-
import {argsEnhancers} from '@storybook/addon-actions/dist/modern/preset/addArgs'
26+
import { argsEnhancers } from "@storybook/addon-actions/dist/modern/preset/addArgs";
2727

28-
import {decorators, parameters} from './preview'
28+
import { decorators, parameters } from "./preview";
2929

3030
if (decorators) {
3131
if (__DEV__) {
3232
// stops the warning from showing on every HMR
33-
require('react-native').LogBox.ignoreLogs([
34-
'`clearDecorators` is deprecated and will be removed in Storybook 7.0',
35-
])
33+
require("react-native").LogBox.ignoreLogs([
34+
"`clearDecorators` is deprecated and will be removed in Storybook 7.0",
35+
]);
3636
}
3737
// workaround for global decorators getting infinitely applied on HMR, see https://github.com/storybookjs/react-native/issues/185
38-
clearDecorators()
39-
decorators.forEach(decorator => addDecorator(decorator))
38+
clearDecorators();
39+
decorators.forEach((decorator) => addDecorator(decorator));
4040
}
4141

4242
if (parameters) {
43-
addParameters(parameters)
43+
addParameters(parameters);
4444
}
4545

4646
try {
47-
argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer))
47+
argsEnhancers.forEach((enhancer) => addArgsEnhancer(enhancer));
4848
} catch {}
4949

5050
const getStories = () => {
5151
return {
5252
"./src/stories/Button.stories.tsx": require("../src/stories/Button.stories.tsx"),
53-
"./src/stories/Progress.stories.tsx": require("../src/stories/Progress.stories.tsx"),
53+
"./src/stories/Checkbox.stories.tsx": require("../src/stories/Checkbox.stories.tsx"),
5454
"./src/stories/CodeInput.stories.tsx": require("../src/stories/CodeInput.stories.tsx"),
55+
"./src/stories/Progress.stories.tsx": require("../src/stories/Progress.stories.tsx"),
56+
"./src/stories/RadioButton.stories.tsx": require("../src/stories/RadioButton.stories.tsx"),
57+
"./src/stories/Switch.stories.tsx": require("../src/stories/Switch.stories.tsx"),
5558
"./src/stories/Text.stories.tsx": require("../src/stories/Text.stories.tsx"),
56-
"./src/stories/Checkbox.stories.tsx": require("../src/stories/Checkbox.stories.tsx"),
57-
'./src/stories/RadioButton.stories.tsx': require('../src/stories/RadioButton.stories.tsx'),
5859
};
5960
};
6061

61-
configure(getStories, module, false)
62+
configure(getStories, module, false);

example/ios/Podfile.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -645,11 +645,11 @@ SPEC CHECKSUMS:
645645
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
646646
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
647647
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
648-
glog: 791fe035093b84822da7f0870421a25839ca7870
649-
hermes-engine: 5d86dc4303697a1251c830f0ee45e6e9f33877d4
648+
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
649+
hermes-engine: a1f157c49ea579c28b0296bda8530e980c45bdb3
650650
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
651651
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
652-
RCT-Folly: 186619bc27c1f94f2f7c6ef60927516c71005915
652+
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
653653
RCTRequired: 5a024fdf458fa8c0d82fc262e76f982d4dcdecdd
654654
RCTTypeSafety: b6c253064466411c6810b45f66bc1e43ce0c54ba
655655
React: 715292db5bd46989419445a5547954b25d2090f0

example/src/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import StorybookUIRoot from '../.ondevice/Storybook'
55
const theme = extendTheme({
66
colors: {
77
cardPrimaryBackground: 'green',
8+
primary: 'grey',
89
},
910
darkColors: {
1011
cardPrimaryBackground: 'gray',
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* eslint-disable react-native/no-inline-styles */
2+
import type {ComponentMeta, ComponentStory} from '@storybook/react'
3+
import React, {useState} from 'react'
4+
5+
import {View} from 'react-native'
6+
import {Switch} from 'rn-base-component'
7+
8+
export default {
9+
title: 'components/Switch',
10+
component: Switch,
11+
} as ComponentMeta<typeof Switch>
12+
13+
export const Basic: ComponentStory<typeof Switch> = args => {
14+
const [isActive, setIsActive] = useState(false)
15+
16+
const onValueChange = () => {
17+
setIsActive(prev => !prev)
18+
}
19+
20+
return (
21+
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
22+
<Switch
23+
{...args}
24+
variant="outside"
25+
value={isActive}
26+
onValueChange={onValueChange}
27+
thumbColor="green"
28+
trackColor={{active: 'blue', inActive: 'gray'}}
29+
/>
30+
</View>
31+
)
32+
}
33+
34+
export const Inside: ComponentStory<typeof Switch> = args => {
35+
const [isActive, setIsActive] = useState(false)
36+
37+
const onValueChange = () => {
38+
setIsActive(prev => !prev)
39+
}
40+
41+
return (
42+
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
43+
<Switch
44+
{...args}
45+
variant="inside"
46+
value={isActive}
47+
onValueChange={onValueChange}
48+
trackColor={{active: 'green', inActive: 'gray'}}
49+
/>
50+
</View>
51+
)
52+
}

example/src/stories/Text.stories.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import React from 'react'
21
import type {ComponentMeta, ComponentStory} from '@storybook/react'
2+
import React from 'react'
33

4-
import {Text, TextBold, TextItalic} from 'rn-base-component'
54
import {StyleSheet, View} from 'react-native'
5+
import {Text, TextBold, TextItalic} from 'rn-base-component'
66
import {metrics} from '../../../src/helpers'
77

88
export default {
9-
title: 'Text',
9+
title: 'components/Text',
1010
component: Text,
1111
} as ComponentMeta<typeof Text>
1212

src/__tests__/switch.test.tsx

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import {fireEvent, render} from '@testing-library/react-native'
2+
import React from 'react'
3+
import {Switch} from '../components'
4+
5+
describe('Switch', () => {
6+
const value = true
7+
const onValueChange = jest.fn()
8+
9+
it('renders without errors', () => {
10+
const {getByTestId} = render(<Switch value={value} onValueChange={onValueChange} />)
11+
const switchContainer = getByTestId('switch-container')
12+
13+
expect(switchContainer).toBeDefined()
14+
})
15+
16+
it('calls onValueChange when pressed', () => {
17+
const {getByTestId} = render(<Switch value={value} onValueChange={onValueChange} />)
18+
const switchContainer = getByTestId('switch-container')
19+
20+
fireEvent.press(switchContainer)
21+
expect(onValueChange).toHaveBeenCalled()
22+
})
23+
24+
it('renders with the correct track color', () => {
25+
const trackColor = 'red'
26+
const {getByTestId} = render(
27+
<Switch value={value} onValueChange={onValueChange} trackColor={trackColor} />,
28+
)
29+
const trackActive = getByTestId('track-active')
30+
const trackInActive = getByTestId('track-in-active')
31+
32+
expect(trackActive.props.style.backgroundColor).toBe(trackColor)
33+
expect(trackInActive.props.style.backgroundColor).toBe(trackColor)
34+
})
35+
36+
it('renders with the correct object track color', () => {
37+
const trackColor = {active: 'red', inActive: 'grey'}
38+
const {getByTestId} = render(
39+
<Switch value={value} onValueChange={onValueChange} trackColor={trackColor} />,
40+
)
41+
const trackActive = getByTestId('track-active')
42+
const trackInActive = getByTestId('track-in-active')
43+
44+
expect(trackActive.props.style.backgroundColor).toBe(trackColor.active)
45+
expect(trackInActive.props.style.backgroundColor).toBe(trackColor.inActive)
46+
})
47+
48+
it('renders with the thembSize prop', () => {
49+
const thumbSize = 20
50+
const {getByTestId} = render(<Switch value={value} onValueChange={onValueChange} thumbSize={thumbSize} />)
51+
const trackActive = getByTestId('track-active')
52+
const trackInActive = getByTestId('track-in-active')
53+
const thumb = getByTestId('thumb')
54+
55+
expect(trackActive.props.thumbSize).toBe(thumbSize)
56+
expect(trackInActive.props.thumbSize).toBe(thumbSize)
57+
expect(thumb.props.thumbSize).toBe(thumbSize)
58+
})
59+
60+
it('renders with the thumbColor prop', () => {
61+
const thumbColor = 'red'
62+
const {getByTestId} = render(
63+
<Switch value={value} onValueChange={onValueChange} thumbColor={thumbColor} />,
64+
)
65+
const thumb = getByTestId('thumb')
66+
67+
expect(thumb.props.thumbColor).toBe(thumbColor)
68+
})
69+
70+
it('disables the component when disabled prop is true', () => {
71+
const {getByTestId} = render(<Switch value={value} onValueChange={onValueChange} disabled />)
72+
const switchContainer = getByTestId('switch-container')
73+
74+
fireEvent.press(switchContainer)
75+
expect(onValueChange).toHaveBeenCalled()
76+
})
77+
78+
it('renders with the correct text inside for active and inactive states', () => {
79+
const textInside = {
80+
active: 'Active',
81+
inActive: 'Inactive',
82+
}
83+
const {getByText} = render(
84+
<Switch value={value} onValueChange={onValueChange} textInside={textInside} variant="inside" />,
85+
)
86+
const labelActive = getByText(textInside.active)
87+
const labelInActive = getByText(textInside.inActive)
88+
89+
expect(labelActive).toBeDefined()
90+
expect(labelInActive).toBeDefined()
91+
})
92+
93+
it('renders with custom text inside color', () => {
94+
const textInsideColor = {
95+
active: 'green',
96+
inActive: 'red',
97+
}
98+
const {getByTestId} = render(
99+
<Switch
100+
value={value}
101+
onValueChange={onValueChange}
102+
textInsideColor={textInsideColor}
103+
variant="inside"
104+
/>,
105+
)
106+
const labelActive = getByTestId('label-active')
107+
const labelInActive = getByTestId('label-in-active')
108+
109+
expect(labelActive.props.color).toBe(textInsideColor.active)
110+
expect(labelInActive.props.color).toBe(textInsideColor.inActive)
111+
})
112+
113+
it('renders with the trackPaddingInside prop with variant inside', () => {
114+
const trackPaddingInside = 4
115+
const {getByTestId} = render(
116+
<Switch
117+
value={value}
118+
onValueChange={onValueChange}
119+
trackPaddingInside={trackPaddingInside}
120+
variant="inside"
121+
/>,
122+
)
123+
const switchContainer = getByTestId('switch-container')
124+
125+
expect(switchContainer.props.trackMargin).toBe(trackPaddingInside)
126+
})
127+
})

0 commit comments

Comments
 (0)