Skip to content

Commit 86f9797

Browse files
authored
Added New Component: CircularSlider (#1)
* Added Circular Slider * Added Component * Added Tests * Added Props * Added README.md * Update package.json * Update package.json
1 parent acfb76f commit 86f9797

File tree

10 files changed

+575
-39
lines changed

10 files changed

+575
-39
lines changed

README.md

+94-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,94 @@
1-
# React Native Elements Universe
1+
<p align="center">
2+
<a href="https://reactnativeelements.com/">
3+
<img alt="react-native-elements" src="https://user-images.githubusercontent.com/5962998/65694309-a825f000-e043-11e9-8382-db0dba0851e3.png" width="300">
4+
</a>
5+
</p>
6+
7+
<p align="center">
8+
Universal Cross Platform <a href="https://reactnative.dev">React Native</a> UI Toolkit
9+
</p>
10+
11+
<p align="center">
12+
<a href="https://www.npmjs.com/package/react-native-elements-universe"><img src="https://img.shields.io/npm/v/react-native-elements-universe.svg"></a>
13+
<a href="https://travis-ci.org/react-native-elements/react-native-elements-universe"><img src="https://img.shields.io/travis/react-native-elements/react-native-elements-universe/master.svg"></a>
14+
<a href="https://github.com/react-native-elements/react-native-elements-universe"><img src="https://img.shields.io/github/stars/react-native-elements/react-native-elements-universe"></a>
15+
<a href="https://www.npmjs.com/package/react-native-elements-universe"><img src="https://img.shields.io/npm/dm/react-native-elements-universe.svg"></a>
16+
<a href="https://react-native-elements-slack.herokuapp.com"><img src="https://react-native-elements-slack.herokuapp.com/badge.svg"></a>
17+
</p>
18+
19+
<p align="center">
20+
<a href="https://codecov.io/gh/react-native-elements/react-native-elements"><img src="https://codecov.io/gh/react-native-elements/react-native-elements-universe/coverage.svg"></a>
21+
<a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/styled_with-prettier-ff69b4.svg"></a>
22+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
23+
24+
</p>
25+
26+
<br />
27+
28+
![React Native Elements UI Toolkit](https://user-images.githubusercontent.com/5962998/37248832-a7060286-24b1-11e8-94a8-847ab6ded4ec.png)
29+
30+
## Get Started
31+
32+
### Installation
33+
34+
Follow
35+
[these instructions](https://reactnativeelements.com/docs/)
36+
to install React Native Elements!
37+
38+
### Usage
39+
40+
Start using the components or try it on Snack
41+
[here](https://snack.expo.io/rJu6gJfBZ).
42+
43+
```js
44+
import { CircularSlider } from 'react-native-elements-universe';
45+
46+
<CircularSlider />;
47+
```
48+
49+
## Components included:
50+
51+
- [x] [CircularSlider](https://reactnativeelements.com/docs/circularslider)
52+
53+
## React Native Web support
54+
55+
As a cross platform UI Toolkit, you can now use RNE on the web & share your codebase between your React Native + React web apps. RNE components are rendered perfectly on browser. You can achieve this to target iOS, Android and Web by collaborating RNE and [React Native for Web](https://github.com/necolas/react-native-web).
56+
57+
Click [here](https://reactnativeelements.com/blog/2018/12/13/react-native-web) for a full walkthrough using React Native Elements + React Native Web.
58+
59+
## Demo App
60+
61+
Checkout the official
62+
[React Native Elements App](https://expo.io/@flyingcircle/projects/react-native-elements-app)
63+
on Expo which uses all of the React Native Elements components.
64+
65+
If you are looking to contribute to the React Native Elements App, click
66+
[here](https://github.com/react-native-elements/react-native-elements-app) to
67+
view the implementation & run the RNE expo app locally.
68+
69+
## Documentation
70+
71+
[View the full docs here](https://reactnativeelements.com/docs/overview)
72+
73+
## Contributing
74+
75+
Interested in contributing to this repo? Check out our
76+
[Contributing Guide](https://reactnativeelements.com/docs/contributing)
77+
and submit a PR for a new feature/bug fix.
78+
79+
A big shoutout to all our contributors! You could be here too!
80+
81+
<a href="https://github.com/react-native-elements/react-native-elements-universe/graphs/contributors"><img src="https://opencollective.com/react-native-elements-universe/contributors.svg?width=890&button=false" /></a>
82+
83+
### First Contributors
84+
85+
We encourage everyone to contribute & submit PR's especially first-time
86+
contributors. Look for the label `Good First Issue` on the issues. Click
87+
[here](https://github.com/react-native-elements/react-native-elements-universe/labels/%F0%9F%91%B6%20Good%20First%20Issue)
88+
to see them.
89+
90+
If there is something you's like to see or request a new feature, please submit
91+
an
92+
[issue](https://github.com/react-native-elements/react-native-elements-universe/issues/new)
93+
or a
94+
[pull request](https://github.com/react-native-elements/react-native-elements-universe/pulls).

package.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,32 @@
4949
},
5050
"devDependencies": {
5151
"@react-native-community/eslint-config": "^2.0.0",
52+
"@testing-library/jest-dom": "^5.11.10",
53+
"@testing-library/react": "^11.2.6",
5254
"@testing-library/react-native": "^7.0.2",
5355
"@types/color": "^3.0.1",
5456
"@types/hoist-non-react-statics": "^3.3.1",
57+
"@types/jest": "^26.0.22",
5558
"@types/lodash.isequal": "^4.5.5",
5659
"@types/react-native": "*",
5760
"@types/react-test-renderer": "^17.0.0",
5861
"auto-changelog": "^2.2.1",
5962
"babel-jest": "^26.3.0",
6063
"eslint": "^7.9.0",
6164
"husky": "^4.3.0",
62-
"jest": "^26.4.2",
65+
"jest": "^26.6.3",
6366
"jest-transform-stub": "^2.0.0",
6467
"lint-staged": "^10.4.0",
6568
"metro-react-native-babel-preset": "^0.63.0",
6669
"react": "^17.0.2",
6770
"react-native": "^0.64.0",
71+
"react-native-elements": "https://github.com/react-native-elements/react-native-elements#dist",
6872
"react-test-renderer": "^16.13.1",
6973
"rimraf": "^3.0.2",
74+
"ts-jest": "^26.5.5",
7075
"typescript": "^4.1.3",
71-
"utility-types": "^3.10.0"
76+
"utility-types": "^3.10.0",
77+
"react-native-svg": "^12.1.1"
7278
},
7379
"peerDependencies": {
7480
"react": "*",

src/CircularSlider/CircularSlider.tsx

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import React from 'react';
2+
import { PanResponder, PanResponderGestureState, View } from 'react-native';
3+
import { RneFunctionComponent } from 'react-native-elements/src/helpers';
4+
import Svg, { Path, Circle, G, Text } from 'react-native-svg';
5+
6+
export type CircularSliderProps = {
7+
trackRadius?: number;
8+
thumbRadius?: number;
9+
trackWidth?: number;
10+
value?: number;
11+
onChange?: (x: number) => any;
12+
trackColor?: string;
13+
thumbColor?: string;
14+
trackTintColor?: string;
15+
thumbTextColor?: string;
16+
thumbTextSize?: number;
17+
noThumb?: boolean;
18+
showText?: boolean;
19+
showThumbText?: boolean;
20+
textColor?: string;
21+
textSize?: number;
22+
minimumValue?: number;
23+
maximumValue?: number;
24+
};
25+
26+
const CircularSlider: RneFunctionComponent<CircularSliderProps> = ({
27+
thumbRadius = 12,
28+
trackRadius = 100,
29+
trackWidth = 5,
30+
trackTintColor,
31+
trackColor,
32+
value = 0,
33+
minimumValue = 0,
34+
maximumValue = 100,
35+
onChange = (x) => x,
36+
thumbTextColor = 'white',
37+
thumbTextSize = 10,
38+
noThumb = false,
39+
showText = false,
40+
showThumbText = false,
41+
thumbColor,
42+
textColor,
43+
textSize = 80,
44+
theme,
45+
}) => {
46+
const [location, setLocation] = React.useState({ x: 0, y: 0 });
47+
const viewRef = React.useRef<View>(null);
48+
const valuePercentage = ((value - minimumValue) * 100) / maximumValue;
49+
50+
const { current: panResponder } = React.useRef(
51+
PanResponder.create({
52+
onStartShouldSetPanResponder: () => true,
53+
onStartShouldSetPanResponderCapture: () => true,
54+
onMoveShouldSetPanResponder: () => true,
55+
onMoveShouldSetPanResponderCapture: () => true,
56+
onPanResponderGrant: () => location.x && location.y,
57+
onPanResponderMove: (_e, { moveX, moveY }: PanResponderGestureState) => {
58+
let angle = cartesianToPolar(moveX - location.x, moveY - location.y);
59+
onChange(angle / 3.6);
60+
},
61+
})
62+
);
63+
64+
const polarToCartesian = React.useCallback(
65+
(angleToChange: number) => {
66+
let r = trackRadius;
67+
let hC = trackRadius + thumbRadius;
68+
let a = ((angleToChange - 90) * Math.PI) / 180.0;
69+
70+
let x = hC + r * Math.cos(a);
71+
let y = hC + r * Math.sin(a);
72+
return { x, y };
73+
},
74+
[trackRadius, thumbRadius]
75+
);
76+
77+
const cartesianToPolar = React.useCallback(
78+
(x, y) => {
79+
let hC = trackRadius + thumbRadius;
80+
81+
if (x === 0) {
82+
return y > hC ? 0 : 180;
83+
} else if (y === 0) {
84+
return x > hC ? 90 : 270;
85+
} else {
86+
return (
87+
Math.round((Math.atan((y - hC) / (x - hC)) * 180) / Math.PI) +
88+
(x > hC ? 90 : 270)
89+
);
90+
}
91+
},
92+
[trackRadius, thumbRadius]
93+
);
94+
95+
const width = (trackRadius + thumbRadius) * 2;
96+
const startCoord = polarToCartesian(0);
97+
const endCoord = polarToCartesian(valuePercentage * 3.6);
98+
99+
return (
100+
<View
101+
style={{ width, height: width }}
102+
ref={viewRef}
103+
onLayout={() => {
104+
viewRef.current?.measure((x, y, w, h, px, py) => {
105+
setLocation({
106+
x: px + w / 2,
107+
y: py + h / 2,
108+
});
109+
});
110+
}}
111+
>
112+
<Svg width={width} height={width} ref={viewRef}>
113+
<Circle
114+
r={trackRadius}
115+
cx={width / 2}
116+
cy={width / 2}
117+
stroke={trackTintColor || theme?.colors?.grey5}
118+
strokeWidth={trackWidth}
119+
/>
120+
121+
<Path
122+
stroke={trackColor || theme?.colors?.primary}
123+
strokeWidth={trackWidth}
124+
fill="none"
125+
d={`M${startCoord.x} ${
126+
startCoord.y
127+
} A ${trackRadius} ${trackRadius} 0 ${
128+
valuePercentage * 3.6 > 180 ? 1 : 0
129+
} 1 ${endCoord.x} ${endCoord.y}`}
130+
/>
131+
{showText && (
132+
<Text
133+
x={trackRadius + thumbRadius}
134+
y={trackRadius + 40}
135+
fontSize={textSize}
136+
fill={textColor || trackColor || theme?.colors?.primary}
137+
textAnchor="middle"
138+
>
139+
{Math.ceil(value).toString()}
140+
</Text>
141+
)}
142+
143+
{!noThumb && (
144+
<G x={endCoord.x - thumbRadius} y={endCoord.y - thumbRadius}>
145+
<Circle
146+
r={thumbRadius}
147+
cx={thumbRadius}
148+
cy={thumbRadius}
149+
fill={thumbColor || trackColor || theme?.colors?.primary}
150+
{...panResponder.panHandlers}
151+
/>
152+
{showThumbText && (
153+
<Text
154+
x={thumbRadius}
155+
y={thumbRadius + thumbTextSize / 2}
156+
fontSize={10}
157+
fill={thumbTextColor || theme?.colors?.white}
158+
textAnchor="middle"
159+
>
160+
{Math.ceil(value).toString().padStart(2, '0')}
161+
</Text>
162+
)}
163+
</G>
164+
)}
165+
</Svg>
166+
</View>
167+
);
168+
};
169+
170+
export default CircularSlider;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
import CircularSlider from './../CircularSlider';
3+
import { render } from '@testing-library/react-native';
4+
5+
test('CircularSlider Component', () => {
6+
const mockFn = jest.fn();
7+
const component = render(<CircularSlider value={80} onChange={mockFn} />);
8+
expect(component).toBeTruthy();
9+
});

src/CircularSlider/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { withTheme } from 'react-native-elements';
2+
import CircularSlider from './CircularSlider';
3+
4+
export type { CircularSliderProps } from './CircularSlider';
5+
export default withTheme(CircularSlider, 'CircularSlider');

src/Example/__tests__/Example.test.js

-8
This file was deleted.

src/Example/index.tsx

-8
This file was deleted.

src/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
import Example from './Example';
1+
// components
2+
export { default as CircularSlider } from './CircularSlider';
23

3-
export { Example };
4+
// types
5+
export type { CircularSliderProps } from './CircularSlider';

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@
4747
"exclude": [
4848
".ci", "website", "node_modules", "babel.config.js", "jest.config.js", "src/index.d.ts", "__tests__"
4949
]
50-
}
50+
}

0 commit comments

Comments
 (0)