react-circular-progressbar
Advanced tools
Comparing version 0.8.1 to 1.0.0
@@ -0,1 +1,60 @@ | ||
## 1.0.0 | ||
We're at 1.0.0! 🎉 Thank you to all the contributors and issue creators. | ||
The main breaking change is the replacement of the `classForPercentage` prop with `className`, and the `textForPercentage` prop with `text` [#61]. | ||
**How to migrate**: | ||
Previously, the text would by default display as "{yourPercentage}%". With 1.0, if you want to display that text, you need to supply the `text` prop explicitly: | ||
```jsx | ||
const percentage = 60; | ||
<CircularProgressbar | ||
percentage={percentage} | ||
text={`${percentage}%`} | ||
/> | ||
``` | ||
If you had customized either `classForPercentage` or `textForPercentage` functions before 1.0, you can reuse the same function for `className` and `text`. | ||
So if your pre-1.0 usage looked like this: | ||
```jsx | ||
function customClassForPercentage(percentage) { | ||
if (percentage < 50) { | ||
return 'red'; | ||
} else { | ||
return 'blue'; | ||
} | ||
} | ||
function customTextForPercentage(percentage) { | ||
if (percentage === 100) { | ||
return `${percentage}!!!`; | ||
} else { | ||
return `${percentage}%`; | ||
} | ||
} | ||
const percentage = 60; | ||
<CircularProgressbar | ||
percentage={percentage} | ||
classForPercentage={customClassForPercentage} | ||
textForPercentage={customTextForPercentage} | ||
/> | ||
``` | ||
...you can make a small change to make it work in 1.0: | ||
```jsx | ||
<CircularProgressbar | ||
percentage={percentage} | ||
className={customClassForPercentage()} | ||
text={customTextForPercentage()} | ||
/> | ||
``` | ||
## 0.8.1 | ||
@@ -2,0 +61,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.CircularProgressbar=t(require("react")):e.CircularProgressbar=t(e.React)}(this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=7)}([function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),u=r(6),c=n(u),l=r(4),p=n(l),f=function(e){function t(e){o(this,t);var r=a(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return r.state={percentage:e.initialAnimation?0:e.percentage},r}return i(t,e),s(t,[{key:"componentDidMount",value:function(){var e=this;this.props.initialAnimation&&(this.initialTimeout=setTimeout(function(){e.requestAnimationFrame=window.requestAnimationFrame(function(){e.setState({percentage:e.props.percentage})})},0))}},{key:"componentWillReceiveProps",value:function(e){this.setState({percentage:e.percentage})}},{key:"componentWillUnmount",value:function(){clearTimeout(this.initialTimeout),window.cancelAnimationFrame(this.requestAnimationFrame)}},{key:"getBackgroundPadding",value:function(){return this.props.background?null==this.props.backgroundPadding?this.props.strokeWidth:this.props.backgroundPadding:0}},{key:"getPathDescription",value:function(){var e=this.getPathRadius(),t=this.props.counterClockwise?1:0;return"\n M 50,50\n m 0,-"+e+"\n a "+e+","+e+" "+t+" 1 1 0,"+2*e+"\n a "+e+","+e+" "+t+" 1 1 0,-"+2*e+"\n "}},{key:"getPathStyles",value:function(){var e=2*Math.PI*this.getPathRadius(),t=Math.min(Math.max(this.state.percentage,0),100),r=(100-t)/100*e;return{strokeDasharray:e+"px "+e+"px",strokeDashoffset:(this.props.counterClockwise?-r:r)+"px"}}},{key:"getPathRadius",value:function(){return 50-this.props.strokeWidth/2-this.getBackgroundPadding()}},{key:"render",value:function(){var e=this.props,t=e.percentage,r=e.textForPercentage,n=e.className,o=e.classes,a=e.styles,i=e.strokeWidth,s=this.props.classForPercentage?this.props.classForPercentage(t):"",u=this.getPathDescription(),l=r?r(t):null;return c.default.createElement("svg",{className:o.root+" "+n+" "+s,style:a.root,viewBox:"0 0 100 100"},this.props.background?c.default.createElement("circle",{className:o.background,style:a.background,cx:50,cy:50,r:50}):null,c.default.createElement("path",{className:o.trail,style:a.trail,d:u,strokeWidth:i,fillOpacity:0}),c.default.createElement("path",{className:o.path,d:u,strokeWidth:i,fillOpacity:0,style:Object.assign({},a.path,this.getPathStyles())}),l?c.default.createElement("text",{className:o.text,style:a.text,x:50,y:50},l):null)}}]),t}(c.default.Component);f.propTypes={percentage:p.default.number.isRequired,className:p.default.string,classes:p.default.objectOf(p.default.string),styles:p.default.objectOf(p.default.object),strokeWidth:p.default.number,background:p.default.bool,backgroundPadding:p.default.number,initialAnimation:p.default.bool,counterClockwise:p.default.bool,classForPercentage:p.default.func,textForPercentage:p.default.func},f.defaultProps={strokeWidth:8,className:"",classes:{root:"CircularProgressbar",trail:"CircularProgressbar-trail",path:"CircularProgressbar-path",text:"CircularProgressbar-text",background:"CircularProgressbar-background"},styles:{root:{},trail:{},path:{},text:{},background:{}},background:!1,backgroundPadding:null,initialAnimation:!1,counterClockwise:!1,classForPercentage:null,textForPercentage:function(e){return e+"%"}},t.default=f},function(e,t,r){"use strict";function n(e){return function(){return e}}var o=function(){};o.thatReturns=n,o.thatReturnsFalse=n(!1),o.thatReturnsTrue=n(!0),o.thatReturnsNull=n(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},e.exports=o},function(e,t,r){"use strict";function n(e,t,r,n,a,i,s,u){if(o(t),!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[r,n,a,i,s,u],p=0;c=new Error(t.replace(/%s/g,function(){return l[p++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var o=function(e){};e.exports=n},function(e,t,r){"use strict";var n=r(1),o=r(2),a=r(5);e.exports=function(){function e(e,t,r,n,i,s){s!==a&&o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var r={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t};return r.checkPropTypes=n,r.PropTypes=r,r}},function(e,t,r){e.exports=r(3)()},function(e,t,r){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(t,r){t.exports=e},function(e,t,r){e.exports=r(0)}])}); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.CircularProgressbar=t(require("react")):e.CircularProgressbar=t(e.React)}(this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=7)}([function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),u=r(6),c=n(u),l=r(4),p=n(l),f=function(e){function t(e){o(this,t);var r=a(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return r.state={percentage:e.initialAnimation?0:e.percentage},r}return i(t,e),s(t,[{key:"componentDidMount",value:function(){var e=this;this.props.initialAnimation&&(this.initialTimeout=setTimeout(function(){e.requestAnimationFrame=window.requestAnimationFrame(function(){e.setState({percentage:e.props.percentage})})},0))}},{key:"componentWillReceiveProps",value:function(e){this.setState({percentage:e.percentage})}},{key:"componentWillUnmount",value:function(){clearTimeout(this.initialTimeout),window.cancelAnimationFrame(this.requestAnimationFrame)}},{key:"getBackgroundPadding",value:function(){return this.props.background?null==this.props.backgroundPadding?this.props.strokeWidth:this.props.backgroundPadding:0}},{key:"getPathDescription",value:function(){var e=this.getPathRadius(),t=this.props.counterClockwise?1:0;return"\n M 50,50\n m 0,-"+e+"\n a "+e+","+e+" "+t+" 1 1 0,"+2*e+"\n a "+e+","+e+" "+t+" 1 1 0,-"+2*e+"\n "}},{key:"getPathStyles",value:function(){var e=2*Math.PI*this.getPathRadius(),t=Math.min(Math.max(this.state.percentage,0),100),r=(100-t)/100*e;return{strokeDasharray:e+"px "+e+"px",strokeDashoffset:(this.props.counterClockwise?-r:r)+"px"}}},{key:"getPathRadius",value:function(){return 50-this.props.strokeWidth/2-this.getBackgroundPadding()}},{key:"render",value:function(){var e=this.props,t=(e.percentage,e.className),r=e.classes,n=e.styles,o=e.strokeWidth,a=e.text,i=this.getPathDescription();return c.default.createElement("svg",{className:r.root+" "+t,style:n.root,viewBox:"0 0 100 100"},this.props.background?c.default.createElement("circle",{className:r.background,style:n.background,cx:50,cy:50,r:50}):null,c.default.createElement("path",{className:r.trail,style:n.trail,d:i,strokeWidth:o,fillOpacity:0}),c.default.createElement("path",{className:r.path,d:i,strokeWidth:o,fillOpacity:0,style:Object.assign({},n.path,this.getPathStyles())}),a?c.default.createElement("text",{className:r.text,style:n.text,x:50,y:50},a):null)}}]),t}(c.default.Component);f.propTypes={percentage:p.default.number.isRequired,className:p.default.string,text:p.default.string,classes:p.default.objectOf(p.default.string),styles:p.default.objectOf(p.default.object),strokeWidth:p.default.number,background:p.default.bool,backgroundPadding:p.default.number,initialAnimation:p.default.bool,counterClockwise:p.default.bool},f.defaultProps={strokeWidth:8,className:"",text:null,classes:{root:"CircularProgressbar",trail:"CircularProgressbar-trail",path:"CircularProgressbar-path",text:"CircularProgressbar-text",background:"CircularProgressbar-background"},styles:{root:{},trail:{},path:{},text:{},background:{}},background:!1,backgroundPadding:null,initialAnimation:!1,counterClockwise:!1},t.default=f},function(e,t,r){"use strict";function n(e){return function(){return e}}var o=function(){};o.thatReturns=n,o.thatReturnsFalse=n(!1),o.thatReturnsTrue=n(!0),o.thatReturnsNull=n(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},e.exports=o},function(e,t,r){"use strict";function n(e,t,r,n,a,i,s,u){if(o(t),!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[r,n,a,i,s,u],p=0;c=new Error(t.replace(/%s/g,function(){return l[p++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var o=function(e){};e.exports=n},function(e,t,r){"use strict";var n=r(1),o=r(2),a=r(5);e.exports=function(){function e(e,t,r,n,i,s){s!==a&&o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var r={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t};return r.checkPropTypes=n,r.PropTypes=r,r}},function(e,t,r){e.exports=r(3)()},function(e,t,r){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(t,r){t.exports=e},function(e,t,r){e.exports=r(0)}])}); |
{ | ||
"name": "react-circular-progressbar", | ||
"version": "0.8.1", | ||
"version": "1.0.0", | ||
"description": "A circular progress indicator component", | ||
@@ -5,0 +5,0 @@ "author": "Kevin Qi <iqnivek@gmail.com>", |
# React Circular Progressbar | ||
A circular progress indicator component, built with SVG. Easily customizable with CSS. [See a live demo](http://www.kevinqi.com/react-circular-progressbar/). | ||
[![npm version](https://badge.fury.io/js/react-circular-progressbar.svg)](https://badge.fury.io/js/react-circular-progressbar) | ||
[![npm version](https://badge.fury.io/js/react-circular-progressbar.svg)](https://www.npmjs.com/package/react-circular-progressbar) | ||
[![Build Status](https://travis-ci.org/iqnivek/react-circular-progressbar.svg?branch=master)](https://travis-ci.org/iqnivek/react-circular-progressbar) | ||
[![Bundle size](https://img.shields.io/bundlephobia/min/react-circular-progressbar.svg)](https://bundlephobia.com/result?p=react-circular-progressbar) | ||
[![react-circular-progressbar animated gif](/docs/react-circular-progressbar.gif?raw=true)](http://www.kevinqi.com/react-circular-progressbar/) | ||
A circular progressbar component, built with SVG and extensively customizable. | ||
[Try it out on CodeSandbox](https://codesandbox.io/s/vymm4oln6y). | ||
<a href="https://codesandbox.io/s/vymm4oln6y"><img height="120" src="/docs/animated-progressbar.gif?raw=true" alt="animated progressbar" /></a> <a href="https://codesandbox.io/s/vymm4oln6y"><img height="120" src="/docs/circular-progressbar-examples.png?raw=true" alt="progressbar examples" /></a> | ||
## Installation | ||
@@ -38,15 +41,18 @@ | ||
If not, you can copy [styles.css](dist/styles.css) into your project instead and use `<link rel="stylesheet" href="styles.css" />` in your `<head>`. | ||
If not, you can copy [styles.css](dist/styles.css) into your project instead, and include `<link rel="stylesheet" href="styles.css" />` in your `<head>`. | ||
Now you can use the component: | ||
```javascript | ||
<CircularProgressbar percentage={60} /> | ||
```jsx | ||
const percentage = 66; | ||
<CircularProgressbar | ||
percentage={percentage} | ||
text={`${percentage}%`} | ||
/> | ||
``` | ||
You can play around with a working example on CodeSandbox: https://codesandbox.io/s/vymm4oln6y | ||
## Props | ||
For examples of how to use props, take a look at the [demo code](docs/demo.jsx) to see JSX for the [live demo page](http://www.kevinqi.com/react-circular-progressbar/). | ||
[**Take a look at the CodeSandbox**](https://codesandbox.io/s/vymm4oln6y) for interactive examples on how to use these props. | ||
@@ -56,38 +62,29 @@ | Name | Description | | ||
| `percentage` | Numeric percentage to display, from 0-100. Required. | | ||
| `className` | Classes to apply to the svg element | | ||
| `className` | Classes to apply to the svg element. Default: `''`. | | ||
| `text` | Text to display inside progressbar. Default: `null`. | | ||
| `strokeWidth` | Width of circular line as a percentage relative to total width of component. Default: `8`. | | ||
| `background` | Whether to display background color. Default: `false`. | | ||
| `backgroundPadding` | Padding between background and edge of svg as a percentage relative to total width of component. Default: `0`. | | ||
| `backgroundPadding` | Padding between background and edge of svg as a percentage relative to total width of component. Default: `null`. | | ||
| `initialAnimation` | Toggle whether to animate progress starting from 0% on initial mount. Default: `false`. | | ||
| `counterClockwise` | Toggle whether to rotate progressbar in counterclockwise direction. Default: `false`. | | ||
| `classForPercentage` | Function which returns an additional class to apply to top-level svg element, which can be used for coloring/styling percentage ranges differently. Example: `(percent) => percent < 100 ? 'incomplete' : 'complete'`. | | ||
| `textForPercentage` | Function which returns text to display, can be configured based on percentage. Example: ``(pct) => `${pct}%` ``. | | ||
| `classes` | Object allowing overrides of classNames of each svg subcomponent (root, trail, path, text, background). Enables styling with react-jss. See [this PR](https://github.com/iqnivek/react-circular-progressbar/pull/25) for more detail. | | ||
| `styles` | Object allowing customization of styles of each svg subcomponent (root, trail, path, text, background). | | ||
Version 1.0.0 removed the `classForPercentage` and `textForPercentage` props in favor of the newer `className` and `text` props. Take a look at the [migration guide](/CHANGELOG.md) for instructions on how to migrate. | ||
## Customizing styles | ||
Use plain CSS to customize the styling - the default CSS is a good starting point, but you can override it as needed. | ||
Use CSS or inline styles to customize the styling - the default CSS is a good starting point, but you can override it as needed. | ||
#### CSS hooks | ||
There are CSS hooks for the path, trail, text, and background of the progressbar which you can customize, e.g.: | ||
```css | ||
.CircularProgressbar-path { stroke: red; } | ||
.CircularProgressbar-trail { stroke: gray; } | ||
.CircularProgressbar-text { fill: yellow; } | ||
.CircularProgressbar-background { fill: green; } | ||
``` | ||
#### Inline style hooks | ||
There are hooks to customize the inline styles of subcomponents of the progressbar (root, path, trail, text, and background). For example, to make the path colored dynamically based on percentage: | ||
There are hooks to customize the inline styles of each subcomponent of the progressbar (the root svg, path, trail, text, and background). | ||
```jsx | ||
<CircularProgressbar | ||
percentage={yourPercentage} | ||
percentage={percentage} | ||
text={`${percentage}%`} | ||
styles={{ | ||
path: { stroke: `rgba(62, 152, 199, ${yourPercentage / 100})` }, | ||
path: { stroke: `rgba(62, 152, 199, ${percentage / 100})` }, | ||
text: { fill: '#f88', fontSize: '16px' }, | ||
}} | ||
@@ -97,14 +94,21 @@ /> | ||
#### Using multiple themes | ||
See `StyledProgressbar.js` in the [CodeSandbox examples](https://codesandbox.io/s/vymm4oln6y) for in-depth examples on how to customize these styles. | ||
You can use the `className` prop to add different classes to the top-level SVG element, and then use that to add different themes to different instances, e.g.: | ||
#### CSS hooks | ||
```javascript | ||
<CircularProgressbar percentage={25} className="progressbar-red" /> | ||
<CircularProgressbar percentage={25} className="progressbar-blue" /> | ||
There are equivalent CSS hooks for the root, path, trail, text, and background of the progressbar which you can customize. | ||
If you're importing the default styles, you can override the defaults like this: | ||
```jsx | ||
import 'react-circular-progressbar/dist/styles.css'; | ||
import './custom.css'; | ||
``` | ||
```css | ||
.progressbar-red .CircularProgressbar-path { stroke: red; } | ||
.progressbar-blue .CircularProgressbar-path { stroke: blue; } | ||
// custom.css | ||
.CircularProgressbar-path { stroke: red; } | ||
.CircularProgressbar-trail { stroke: gray; } | ||
.CircularProgressbar-text { fill: yellow; } | ||
.CircularProgressbar-background { fill: green; } | ||
``` | ||
@@ -122,11 +126,9 @@ | ||
## Development | ||
## Contributing | ||
To run demo locally on localhost:8080: | ||
Take a look at [CONTRIBUTING.md](/CONTRIBUTING.md) to see how to develop on react-circular-progressbar. | ||
```bash | ||
yarn install | ||
yarn start | ||
``` | ||
Keep tests passing by running `yarn test` and `yarn run lint`. | ||
## License | ||
[MIT](/LICENSE) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
17968
2
131