Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,94 @@
# React Native Elements Universe
<p align="center">
<a href="https://reactnativeelements.com/">
<img alt="react-native-elements" src="https://user-images.githubusercontent.com/5962998/65694309-a825f000-e043-11e9-8382-db0dba0851e3.png" width="300">
</a>
</p>

<p align="center">
Universal Cross Platform <a href="https://reactnative.dev">React Native</a> UI Toolkit
</p>

<p align="center">
<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>
<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>
<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>
<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>
<a href="https://react-native-elements-slack.herokuapp.com"><img src="https://react-native-elements-slack.herokuapp.com/badge.svg"></a>
</p>

<p align="center">
<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>
<a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/styled_with-prettier-ff69b4.svg"></a>
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>

</p>

<br />

![React Native Elements UI Toolkit](https://user-images.githubusercontent.com/5962998/37248832-a7060286-24b1-11e8-94a8-847ab6ded4ec.png)

## Get Started

### Installation

Follow
[these instructions](https://reactnativeelements.com/docs/)
to install React Native Elements!

### Usage

Start using the components or try it on Snack
[here](https://snack.expo.io/rJu6gJfBZ).

```js
import { CircularSlider } from 'react-native-elements-universe';

<CircularSlider />;
```

## Components included:

- [x] [CircularSlider](https://reactnativeelements.com/docs/circularslider)

## React Native Web support

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).

Click [here](https://reactnativeelements.com/blog/2018/12/13/react-native-web) for a full walkthrough using React Native Elements + React Native Web.

## Demo App

Checkout the official
[React Native Elements App](https://expo.io/@flyingcircle/projects/react-native-elements-app)
on Expo which uses all of the React Native Elements components.

If you are looking to contribute to the React Native Elements App, click
[here](https://github.com/react-native-elements/react-native-elements-app) to
view the implementation & run the RNE expo app locally.

## Documentation

[View the full docs here](https://reactnativeelements.com/docs/overview)

## Contributing

Interested in contributing to this repo? Check out our
[Contributing Guide](https://reactnativeelements.com/docs/contributing)
and submit a PR for a new feature/bug fix.

A big shoutout to all our contributors! You could be here too!

<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>

### First Contributors

We encourage everyone to contribute & submit PR's especially first-time
contributors. Look for the label `Good First Issue` on the issues. Click
[here](https://github.com/react-native-elements/react-native-elements-universe/labels/%F0%9F%91%B6%20Good%20First%20Issue)
to see them.

If there is something you's like to see or request a new feature, please submit
an
[issue](https://github.com/react-native-elements/react-native-elements-universe/issues/new)
or a
[pull request](https://github.com/react-native-elements/react-native-elements-universe/pulls).
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,32 @@
},
"devDependencies": {
"@react-native-community/eslint-config": "^2.0.0",
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/react-native": "^7.0.2",
"@types/color": "^3.0.1",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/jest": "^26.0.22",
"@types/lodash.isequal": "^4.5.5",
"@types/react-native": "*",
"@types/react-test-renderer": "^17.0.0",
"auto-changelog": "^2.2.1",
"babel-jest": "^26.3.0",
"eslint": "^7.9.0",
"husky": "^4.3.0",
"jest": "^26.4.2",
"jest": "^26.6.3",
"jest-transform-stub": "^2.0.0",
"lint-staged": "^10.4.0",
"metro-react-native-babel-preset": "^0.63.0",
"react": "^17.0.2",
"react-native": "^0.64.0",
"react-native-elements": "https://github.com/react-native-elements/react-native-elements#dist",
"react-test-renderer": "^16.13.1",
"rimraf": "^3.0.2",
"ts-jest": "^26.5.5",
"typescript": "^4.1.3",
"utility-types": "^3.10.0"
"utility-types": "^3.10.0",
"react-native-svg": "^12.1.1"
},
"peerDependencies": {
"react": "*",
Expand Down
170 changes: 170 additions & 0 deletions src/CircularSlider/CircularSlider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React from 'react';
import { PanResponder, PanResponderGestureState, View } from 'react-native';
import { RneFunctionComponent } from 'react-native-elements/src/helpers';
import Svg, { Path, Circle, G, Text } from 'react-native-svg';

export type CircularSliderProps = {
trackRadius?: number;
thumbRadius?: number;
trackWidth?: number;
value?: number;
onChange?: (x: number) => any;
trackColor?: string;
thumbColor?: string;
trackTintColor?: string;
thumbTextColor?: string;
thumbTextSize?: number;
noThumb?: boolean;
showText?: boolean;
showThumbText?: boolean;
textColor?: string;
textSize?: number;
minimumValue?: number;
maximumValue?: number;
};

const CircularSlider: RneFunctionComponent<CircularSliderProps> = ({
thumbRadius = 12,
trackRadius = 100,
trackWidth = 5,
trackTintColor,
trackColor,
value = 0,
minimumValue = 0,
maximumValue = 100,
onChange = (x) => x,
thumbTextColor = 'white',
thumbTextSize = 10,
noThumb = false,
showText = false,
showThumbText = false,
thumbColor,
textColor,
textSize = 80,
theme,
}) => {
const [location, setLocation] = React.useState({ x: 0, y: 0 });
const viewRef = React.useRef<View>(null);
const valuePercentage = ((value - minimumValue) * 100) / maximumValue;

const { current: panResponder } = React.useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: () => location.x && location.y,
onPanResponderMove: (_e, { moveX, moveY }: PanResponderGestureState) => {
let angle = cartesianToPolar(moveX - location.x, moveY - location.y);
onChange(angle / 3.6);
},
})
);

const polarToCartesian = React.useCallback(
(angleToChange: number) => {
let r = trackRadius;
let hC = trackRadius + thumbRadius;
let a = ((angleToChange - 90) * Math.PI) / 180.0;

let x = hC + r * Math.cos(a);
let y = hC + r * Math.sin(a);
return { x, y };
},
[trackRadius, thumbRadius]
);

const cartesianToPolar = React.useCallback(
(x, y) => {
let hC = trackRadius + thumbRadius;

if (x === 0) {
return y > hC ? 0 : 180;
} else if (y === 0) {
return x > hC ? 90 : 270;
} else {
return (
Math.round((Math.atan((y - hC) / (x - hC)) * 180) / Math.PI) +
(x > hC ? 90 : 270)
);
}
},
[trackRadius, thumbRadius]
);

const width = (trackRadius + thumbRadius) * 2;
const startCoord = polarToCartesian(0);
const endCoord = polarToCartesian(valuePercentage * 3.6);

return (
<View
style={{ width, height: width }}
ref={viewRef}
onLayout={() => {
viewRef.current?.measure((x, y, w, h, px, py) => {
setLocation({
x: px + w / 2,
y: py + h / 2,
});
});
}}
>
<Svg width={width} height={width} ref={viewRef}>
<Circle
r={trackRadius}
cx={width / 2}
cy={width / 2}
stroke={trackTintColor || theme?.colors?.grey5}
strokeWidth={trackWidth}
/>

<Path
stroke={trackColor || theme?.colors?.primary}
strokeWidth={trackWidth}
fill="none"
d={`M${startCoord.x} ${
startCoord.y
} A ${trackRadius} ${trackRadius} 0 ${
valuePercentage * 3.6 > 180 ? 1 : 0
} 1 ${endCoord.x} ${endCoord.y}`}
/>
{showText && (
<Text
x={trackRadius + thumbRadius}
y={trackRadius + 40}
fontSize={textSize}
fill={textColor || trackColor || theme?.colors?.primary}
textAnchor="middle"
>
{Math.ceil(value).toString()}
</Text>
)}

{!noThumb && (
<G x={endCoord.x - thumbRadius} y={endCoord.y - thumbRadius}>
<Circle
r={thumbRadius}
cx={thumbRadius}
cy={thumbRadius}
fill={thumbColor || trackColor || theme?.colors?.primary}
{...panResponder.panHandlers}
/>
{showThumbText && (
<Text
x={thumbRadius}
y={thumbRadius + thumbTextSize / 2}
fontSize={10}
fill={thumbTextColor || theme?.colors?.white}
textAnchor="middle"
>
{Math.ceil(value).toString().padStart(2, '0')}
</Text>
)}
</G>
)}
</Svg>
</View>
);
};

export default CircularSlider;
9 changes: 9 additions & 0 deletions src/CircularSlider/__tests__/CircularSlider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import CircularSlider from './../CircularSlider';
import { render } from '@testing-library/react-native';

test('CircularSlider Component', () => {
const mockFn = jest.fn();
const component = render(<CircularSlider value={80} onChange={mockFn} />);
expect(component).toBeTruthy();
});
5 changes: 5 additions & 0 deletions src/CircularSlider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { withTheme } from 'react-native-elements';
import CircularSlider from './CircularSlider';

export type { CircularSliderProps } from './CircularSlider';
export default withTheme(CircularSlider, 'CircularSlider');
8 changes: 0 additions & 8 deletions src/Example/__tests__/Example.test.js

This file was deleted.

8 changes: 0 additions & 8 deletions src/Example/index.tsx

This file was deleted.

6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Example from './Example';
// components
export { default as CircularSlider } from './CircularSlider';

export { Example };
// types
export type { CircularSliderProps } from './CircularSlider';
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@
"exclude": [
".ci", "website", "node_modules", "babel.config.js", "jest.config.js", "src/index.d.ts", "__tests__"
]
}
}
Loading