react-countup
Advanced tools
Comparing version 3.0.3 to 4.0.0-alpha.0
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.startAnimation = exports.formatNumber = undefined; | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var Count = _interopDefault(require('countup.js')); | ||
var PropTypes = _interopDefault(require('prop-types')); | ||
var React = require('react'); | ||
var React__default = _interopDefault(React); | ||
var warning = _interopDefault(require('warning')); | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _react = require('react'); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _react2 = _interopRequireDefault(_react); | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
var _countup = require('countup.js'); | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
var _countup2 = _interopRequireDefault(_countup); | ||
var CountUp = function (_Component) { | ||
_inherits(CountUp, _Component); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function CountUp() { | ||
var _ref; | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _temp, _this, _ret; | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
_classCallCheck(this, CountUp); | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
// Adapted from the countup.js format number function | ||
// https://github.com/inorganik/countUp.js/blob/master/countUp.js#L46-L60 | ||
var formatNumber = exports.formatNumber = function formatNumber(start, options) { | ||
var neg = start < 0; | ||
var num = '' + Math.abs(start).toFixed(options.decimals); | ||
var x = num.split('.'); | ||
var x1 = x[0]; | ||
var x2 = x.length > 1 ? '' + options.decimal + x[1] : ''; | ||
var rgx = /(\d+)(\d{3})/; | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = CountUp.__proto__ || Object.getPrototypeOf(CountUp)).call.apply(_ref, [this].concat(args))), _this), _this.createInstance = function () { | ||
// Warn when user didn't use containerRef at all | ||
warning(_this.containerRef.current && _this.containerRef.current instanceof HTMLElement, 'Couldn\'t find attached element to hook the CountUp instance into! Try to attach "containerRef" from the render prop to a an HTMLElement, eg. <span ref={containerRef} />.'); | ||
if (options.separator) { | ||
while (rgx.test(x1)) { | ||
x1 = x1.replace(rgx, '$1' + options.separator + '$2'); | ||
} | ||
} | ||
var _this$props = _this.props, | ||
decimal = _this$props.decimal, | ||
decimals = _this$props.decimals, | ||
duration = _this$props.duration, | ||
easingFn = _this$props.easingFn, | ||
end = _this$props.end, | ||
formattingFn = _this$props.formattingFn, | ||
prefix = _this$props.prefix, | ||
separator = _this$props.separator, | ||
start = _this$props.start, | ||
suffix = _this$props.suffix, | ||
useEasing = _this$props.useEasing; | ||
return '' + (neg ? '-' : '') + (options.prefix || '') + x1 + x2 + (options.suffix || ''); | ||
}; | ||
var startAnimation = exports.startAnimation = function startAnimation(component) { | ||
if (!(component && component.spanElement)) { | ||
throw new Error('You need to pass the CountUp component as an argument!\neg. this.myCountUp.startAnimation(this.myCountUp);'); | ||
} | ||
return new Count(_this.containerRef.current, start, end, decimals, duration, { | ||
decimal: decimal, | ||
easingFn: easingFn, | ||
formattingFn: formattingFn, | ||
separator: separator, | ||
prefix: prefix, | ||
suffix: suffix, | ||
useEasing: useEasing, | ||
useGrouping: !!separator | ||
}); | ||
}, _this.pauseResume = function () { | ||
var _this2 = _this, | ||
reset = _this2.reset, | ||
start = _this2.restart, | ||
update = _this2.update; | ||
var onPauseResume = _this.props.onPauseResume; | ||
var _component$props = component.props, | ||
decimal = _component$props.decimal, | ||
decimals = _component$props.decimals, | ||
duration = _component$props.duration, | ||
easingFn = _component$props.easingFn, | ||
end = _component$props.end, | ||
formattingFn = _component$props.formattingFn, | ||
onComplete = _component$props.onComplete, | ||
onStart = _component$props.onStart, | ||
prefix = _component$props.prefix, | ||
separator = _component$props.separator, | ||
start = _component$props.start, | ||
suffix = _component$props.suffix, | ||
useEasing = _component$props.useEasing; | ||
_this.instance.pauseResume(); | ||
var countupInstance = new _countup2.default(component.spanElement, start, end, decimals, duration, { | ||
decimal: decimal, | ||
easingFn: easingFn, | ||
formattingFn: formattingFn, | ||
separator: separator, | ||
prefix: prefix, | ||
suffix: suffix, | ||
useEasing: useEasing, | ||
useGrouping: !!separator | ||
}); | ||
onPauseResume({ reset: reset, start: start, update: update }); | ||
}, _this.reset = function () { | ||
var _this3 = _this, | ||
pauseResume = _this3.pauseResume, | ||
start = _this3.restart, | ||
update = _this3.update; | ||
var onReset = _this.props.onReset; | ||
if (typeof onStart === 'function') { | ||
onStart(); | ||
} | ||
countupInstance.start(onComplete); | ||
}; | ||
_this.instance.reset(); | ||
var CountUp = function (_React$Component) { | ||
_inherits(CountUp, _React$Component); | ||
onReset({ pauseResume: pauseResume, start: start, update: update }); | ||
}, _this.restart = function () { | ||
_this.reset(); | ||
_this.start(); | ||
}, _this.start = function () { | ||
var _this4 = _this, | ||
pauseResume = _this4.pauseResume, | ||
reset = _this4.reset, | ||
start = _this4.restart, | ||
update = _this4.update; | ||
var _this$props2 = _this.props, | ||
onEnd = _this$props2.onEnd, | ||
onStart = _this$props2.onStart; | ||
function CountUp() { | ||
var _ref; | ||
var _temp, _this, _ret; | ||
_this.instance.start(function () { | ||
return onEnd({ pauseResume: pauseResume, reset: reset, start: start, update: update }); | ||
}); | ||
_classCallCheck(this, CountUp); | ||
onStart({ pauseResume: pauseResume, reset: reset, update: update }); | ||
}, _this.update = function (newEnd) { | ||
var _this5 = _this, | ||
pauseResume = _this5.pauseResume, | ||
reset = _this5.reset, | ||
start = _this5.restart; | ||
var onUpdate = _this.props.onUpdate; | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = CountUp.__proto__ || Object.getPrototypeOf(CountUp)).call.apply(_ref, [this].concat(args))), _this), _this.spanElement = null, _this.refSpan = function (span) { | ||
_this.spanElement = span; | ||
}, _temp), _possibleConstructorReturn(_this, _ret); | ||
_this.instance.update(newEnd); | ||
onUpdate({ pauseResume: pauseResume, reset: reset, start: start }); | ||
}, _this.containerRef = React__default.createRef(), _temp), _possibleConstructorReturn(_this, _ret); | ||
} | ||
@@ -106,3 +119,16 @@ | ||
value: function componentDidMount() { | ||
startAnimation(this); | ||
var _props = this.props, | ||
children = _props.children, | ||
delay = _props.delay; | ||
this.instance = this.createInstance(); | ||
// Delay start if delay prop is properly set | ||
if (delay > 0) return setTimeout(this.start, delay * 1000); | ||
// Don't invoke start if the component is used as a render prop | ||
if (typeof children === 'function') return; | ||
// Otherwise just start immediately | ||
this.start(); | ||
} | ||
@@ -114,8 +140,21 @@ }, { | ||
return nextProps.redraw || hasCertainPropsChanged; | ||
return hasCertainPropsChanged || this.props.redraw; | ||
} | ||
}, { | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate() { | ||
startAnimation(this); | ||
value: function componentDidUpdate(prevProps) { | ||
// If duration or start has changed, there's no way to update the duration | ||
// or start value. So we need to re-create the CountUp instance in order to | ||
// restart it. | ||
if (this.props.duration !== prevProps.duration || this.props.start !== prevProps.start) { | ||
this.instance = this.createInstance(); | ||
this.start(); | ||
} | ||
// Only end value has changed, so reset and and re-animate with the updated | ||
// end value. | ||
if (this.props.end !== prevProps.end) { | ||
this.instance.reset(); | ||
this.instance.update(this.props.end); | ||
} | ||
} | ||
@@ -125,25 +164,24 @@ }, { | ||
value: function render() { | ||
var _props = this.props, | ||
className = _props.className, | ||
start = _props.start, | ||
decimal = _props.decimal, | ||
decimals = _props.decimals, | ||
separator = _props.separator, | ||
prefix = _props.prefix, | ||
suffix = _props.suffix, | ||
style = _props.style, | ||
formattingFn = _props.formattingFn; | ||
var _props2 = this.props, | ||
children = _props2.children, | ||
className = _props2.className, | ||
style = _props2.style; | ||
var containerRef = this.containerRef, | ||
pauseResume = this.pauseResume, | ||
reset = this.reset, | ||
restart = this.restart, | ||
update = this.update; | ||
return _react2.default.createElement( | ||
'span', | ||
{ className: className, ref: this.refSpan, style: style }, | ||
typeof formattingFn === 'function' ? formattingFn(start) : formatNumber(start, { | ||
decimal: decimal, | ||
decimals: decimals, | ||
separator: separator, | ||
prefix: prefix, | ||
suffix: suffix | ||
}) | ||
); | ||
if (typeof children === 'function') { | ||
return children({ | ||
countUpRef: containerRef, | ||
pauseResume: pauseResume, | ||
reset: reset, | ||
start: restart, | ||
update: update | ||
}); | ||
} | ||
return React__default.createElement('span', { className: className, ref: containerRef, style: style }); | ||
} | ||
@@ -153,22 +191,42 @@ }]); | ||
return CountUp; | ||
}(_react2.default.Component); | ||
}(React.Component); | ||
CountUp.propTypes = { | ||
decimal: PropTypes.string, | ||
decimals: PropTypes.number, | ||
delay: PropTypes.number, | ||
easingFn: PropTypes.func, | ||
end: PropTypes.number.isRequired, | ||
formattingFn: PropTypes.func, | ||
onEnd: PropTypes.func, | ||
onStart: PropTypes.func, | ||
prefix: PropTypes.string, | ||
redraw: PropTypes.bool, | ||
separator: PropTypes.string, | ||
start: PropTypes.number, | ||
suffix: PropTypes.string, | ||
style: PropTypes.object, | ||
useEasing: PropTypes.bool | ||
}; | ||
CountUp.defaultProps = { | ||
className: undefined, | ||
decimal: '.', | ||
decimals: 0, | ||
duration: 3, | ||
delay: 0, | ||
duration: null, | ||
easingFn: null, | ||
end: 100, | ||
formattingFn: null, | ||
onComplete: undefined, | ||
onStart: undefined, | ||
onEnd: function onEnd() {}, | ||
onPauseResume: function onPauseResume() {}, | ||
onReset: function onReset() {}, | ||
onStart: function onStart() {}, | ||
onUpdate: function onUpdate() {}, | ||
prefix: '', | ||
redraw: false, | ||
separator: '', | ||
start: 0, | ||
suffix: '', | ||
redraw: false, | ||
style: undefined, | ||
useEasing: true | ||
}; | ||
exports.default = CountUp; | ||
module.exports = CountUp; |
{ | ||
"name": "react-countup", | ||
"version": "3.0.3", | ||
"version": "4.0.0-alpha.0", | ||
"description": "A React component wrapper around CountUp.js", | ||
@@ -16,6 +16,3 @@ "author": "Glenn Reyes <glenn@glennreyes.com> (https://twitter.com/glnnrys)", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/glennreyes/react-countup.git" | ||
}, | ||
"repository": "glennreyes/react-countup", | ||
"bugs": { | ||
@@ -31,39 +28,41 @@ "url": "https://github.com/glennreyes/react-countup/issues" | ||
"scripts": { | ||
"build": "babel src -d build --ignore __tests__", | ||
"flow": "flow check", | ||
"lint": "eslint src", | ||
"build": "rollup -c", | ||
"precommit": "lint-staged", | ||
"prepare": "yarn run build", | ||
"prettier": "prettier --write src/**/*.js", | ||
"prepublishOnly": "yarn build", | ||
"test": "jest" | ||
}, | ||
"peerDependencies": { | ||
"react": "^16.0.0" | ||
"react": ">= 16.3.0" | ||
}, | ||
"dependencies": { | ||
"countup.js": "^1.9.3" | ||
"countup.js": "^1.9.3", | ||
"prop-types": "^15.6.2", | ||
"warning": "^4.0.1" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-eslint": "^8.0.2", | ||
"babel-preset-env": "^1.6.1", | ||
"babel-core": "^6.26.3", | ||
"babel-eslint": "^7.2.3", | ||
"babel-plugin-transform-class-properties": "^6.24.1", | ||
"babel-preset-env": "^1.7.0", | ||
"babel-preset-react": "^6.24.1", | ||
"babel-preset-stage-2": "^6.24.1", | ||
"eslint": "^4.11.0", | ||
"eslint-config-airbnb": "^16.1.0", | ||
"eslint-config-prettier": "^2.7.0", | ||
"eslint-plugin-flowtype": "^2.39.1", | ||
"eslint-plugin-import": "^2.7.0", | ||
"eslint-plugin-jsx-a11y": "^6.0.2", | ||
"eslint-plugin-react": "^7.4.0", | ||
"flow-bin": "^0.59.0", | ||
"eslint": "^4.19.1", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-config-react-app": "^2.1.0", | ||
"eslint-plugin-flowtype": "^2.50.0", | ||
"eslint-plugin-import": "^2.13.0", | ||
"eslint-plugin-jsx-a11y": "^5.1.1", | ||
"eslint-plugin-prettier": "^2.6.2", | ||
"eslint-plugin-react": "^7.10.0", | ||
"husky": "^0.14.3", | ||
"jest": "^21.2.1", | ||
"lint-staged": "^5.0.0", | ||
"prettier": "^1.8.2", | ||
"jest": "^23.4.2", | ||
"lint-staged": "^7.2.0", | ||
"prettier": "^1.14.1", | ||
"raf": "^3.4.0", | ||
"react": "^16.1.1", | ||
"react-dom": "^16.1.1", | ||
"react-test-renderer": "^16.1.1" | ||
"react": "^16.4.1", | ||
"react-dom": "^16.4.1", | ||
"react-test-renderer": "^16.4.2", | ||
"react-testing-library": "^4.1.7", | ||
"rollup": "^0.64.1", | ||
"rollup-plugin-babel": "^3.0.7" | ||
} | ||
} |
319
README.md
@@ -1,20 +0,51 @@ | ||
# [React CountUp](https://glennreyes.github.io/react-countup) | ||
# React CountUp | ||
[![Build Status](https://travis-ci.org/glennreyes/react-countup.svg?branch=master)](https://travis-ci.org/glennreyes/react-countup) | ||
[![Coverage Status](https://coveralls.io/repos/github/glennreyes/react-countup/badge.svg?branch=master)](https://coveralls.io/github/glennreyes/react-countup?branch=master) | ||
[![Dependency Status](https://david-dm.org/glennreyes/react-countup.svg)](https://david-dm.org/glennreyes/react-countup) | ||
[![Dependency Status](https://david-dm.org/glennreyes/react-countup/dev-status.svg)](https://david-dm.org/glennreyes/react-countup#info=devDependencies) | ||
[![npm version](https://badge.fury.io/js/react-countup.svg)](https://badge.fury.io/js/react-countup) | ||
[![GitHub license](https://img.shields.io/npm/l/react-countup.svg?style=flat-square)](https://github.com/glennreyes/react-countup/blob/master/LICENSE) | ||
[![Build Status](https://img.shields.io/travis/glennreyes/react-countup.svg?style=flat-square)](https://travis-ci.org/glennreyes/react-countup) | ||
[![Coverage Status](https://img.shields.io/coveralls/glennreyes/react-countup.svg?style=flat-square)](https://coveralls.io/github/glennreyes/react-countup) | ||
[![Version](https://img.shields.io/npm/v/react-countup.svg?style=flat-square)](https://www.npmjs.com/package/react-countup) | ||
[![Downloads](https://img.shields.io/npm/dm/react-countup.svg?style=flat-square)](http://www.npmtrends.com/react-countup) | ||
[![Gzip size](https://img.badgesize.io/https://unpkg.com/react-countup?style=flat-square&compression=gzip)](https://img.badgesize.io/https://unpkg.com/react-countup) | ||
A configurable React component wrapper around [CountUp.js](https://inorganik.github.io/countUp.js/). | ||
![sep -15-2016 10-11-53 pm](https://cloud.githubusercontent.com/assets/5080854/18565869/d23db0e0-7b91-11e6-9ee2-71be5875ca48.gif) | ||
## Table of Contents | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Simple example](#simple-example) | ||
- [Advanced example](#render-prop-example) | ||
- [More examples](#more-examples) | ||
- [Manually start](#manually-start) | ||
- [Delay start](#delay-start) | ||
- [API](#api) | ||
- [Props](#props) | ||
- [`className: string`](#classname-string) | ||
- [`decimal: string`](#decimal-string) | ||
- [`decimals: number`](#decimals-number) | ||
- [`delay: number`](#delay-number) | ||
- [`duration: number`](#duration-number) | ||
- [`end: number`](#end-number) | ||
- [`prefix: string`](#prefix-string) | ||
- [`redraw: boolean`](#redraw-boolean) | ||
- [`separator: string`](#separator-string) | ||
- [`start: number`](#start-number) | ||
- [`suffix: string`](#suffix-string) | ||
- [`useEasing: boolean`](#useeasing-boolean) | ||
- [`easingFn: (t: number, b: number, c: number, d: number) => number`](#easingfn-t-number-b-number-c-number-d-number--number) | ||
- [`formattingFn: (value: number) => string`](#formattingfn-value-number--string) | ||
- [`onEnd: ({ pauseResume, reset, start, update }) => void`](#onend--pauseresume-reset-start-update---void) | ||
- [`onStart: ({ pauseResume, reset, update }) => void`](#onstart--pauseresume-reset-update---void) | ||
- [`onPauseResume: ({ reset, start, update }) => void`](#onpauseresume--reset-start-update---void) | ||
- [`onReset: ({ pauseResume, start, update }) => void`](#onreset--pauseresume-start-update---void) | ||
- [`onUpdate: ({ pauseResume, reset, start }) => void`](#onupdate--pauseresume-reset-start---void) | ||
- [Render props](#render-props) | ||
- [`countUpRef: () => void`](#countupref---void) | ||
- [`pauseResume: () => void`](#pauseresume---void) | ||
- [`reset: () => void`](#reset---void) | ||
- [`start: () => void`](#start---void) | ||
- [`update: (newEnd: number?) => void`](#update-newend-number--void) | ||
- [Protips](#protips) | ||
- [License](#license) | ||
## [Demo](https://glennreyes.github.io/react-countup) | ||
Check out the [demo](https://glennreyes.github.io/react-countup). | ||
## Installation | ||
@@ -26,108 +57,207 @@ | ||
Alternatively with npm: | ||
```bash | ||
npm install react-countup --save | ||
## Usage | ||
```js | ||
import CountUp from 'react-countup'; | ||
``` | ||
### Simple example | ||
## Usage | ||
```js | ||
<CountUp end={100} /> | ||
``` | ||
#### Simple | ||
This will start a count up transition from `0` to `100` on render. | ||
### Render prop example | ||
```js | ||
import React from 'react'; | ||
import { render } from 'react-dom'; | ||
import CountUp from 'react-countup'; | ||
<CountUp | ||
className="account-balance" | ||
start={-875.039} | ||
end={160527.012} | ||
duration={2.75} | ||
separator=" " | ||
decimals={4} | ||
decimal="," | ||
prefix="EUR " | ||
suffix=" left" | ||
onEnd={() => console.log('Ended! 👏')} | ||
onStart={() => console.log('Started! 💨')} | ||
> | ||
{({ countUpRef, start }) => ( | ||
<div> | ||
<span ref={countUpRef} /> | ||
<button onClick={start}>Start</button> | ||
</div> | ||
)} | ||
</CountUp> | ||
``` | ||
render( | ||
<CountUp start={0} end={160526} />, | ||
document.getElementById('root') | ||
); | ||
The transition won't start on initial render as it needs to be triggered manually here. | ||
> Tip: If you need to start the render prop component immediately, you can set delay={0}. | ||
### More examples | ||
#### Autostart with render prop | ||
Render start value but start transition on first render: | ||
```js | ||
<CountUp start={0} end={100} delay={0}> | ||
{({ countUpRef, start }) => ( | ||
<div> | ||
<span ref={countUpRef} /> | ||
<button onClick={start}>Start</button> | ||
</div> | ||
)} | ||
</CountUp> | ||
``` | ||
#### Advanced | ||
Render start value and start transition: | ||
```js | ||
import React from 'react'; | ||
import { render } from 'react-dom'; | ||
import CountUp from 'react-countup'; | ||
<CountUp start={0} end={100}> | ||
{({ countUpref, start }) => ( | ||
<div> | ||
<span ref={countUpRef} /> | ||
<button onClick={start}>Start</button> | ||
</div> | ||
)} | ||
</CountUp> | ||
``` | ||
const onComplete = () => { | ||
console.log('Completed! 👏'); | ||
}; | ||
#### Delay start | ||
const onStart = () => { | ||
console.log('Started! 💨'); | ||
}; | ||
render( | ||
<CountUp | ||
className="account-balance" | ||
start={160527.0127} | ||
end={-875.0319} | ||
duration={2.75} | ||
useEasing={true} | ||
useGrouping={true} | ||
separator=" " | ||
decimals={4} | ||
decimal="," | ||
prefix="EUR " | ||
suffix=" left" | ||
onComplete={onComplete} | ||
onStart={onStart} | ||
/>, | ||
document.getElementById('root'), | ||
); | ||
```js | ||
<CountUp delay={2} end={100} /> | ||
``` | ||
## API | ||
### Props | ||
##### `start`: number | ||
Start value | ||
#### `className: string` | ||
##### `end`: number | ||
Target value | ||
CSS class name of the span element. | ||
##### `duration`: number | ||
Duration in seconds | ||
> Note: This won't be applied when using CountUp with render props. | ||
##### `decimals`: number | ||
Amount of decimals | ||
#### `decimal: string` | ||
##### `useEasing`: boolean | ||
Enable easing if set to `true` (default easing: `easeOutExpo`) | ||
Specifies decimal character. | ||
##### `separator`: string | ||
Specifies character of thousands separator | ||
Default: `.` | ||
##### `decimal`: string | ||
Specifies decimal character | ||
#### `decimals: number` | ||
##### `prefix`: string | ||
Static text before the animating value | ||
Amount of decimals to display. | ||
##### `suffix`: string | ||
Static text after the animating value | ||
Default: `0` | ||
##### `className`: string | ||
CSS class name of the span element | ||
#### `delay: number` | ||
##### `redraw`: boolean | ||
If set to `true`, the CountUp component will always animate on every re-render. | ||
Delay in seconds before starting the transition. | ||
##### `onComplete`: function | ||
Function called after animation has completed | ||
Default: `null` | ||
##### `onStart`: function | ||
Function called before animation starts | ||
> Note: `delay={0}` will automatically start the count up. | ||
##### `easingFn`: function | ||
Easing function, see [here for instructions](https://github.com/inorganik/countUp.js#custom-easing) | ||
#### `duration: number` | ||
##### `formattingFn`: function | ||
Duration in seconds. | ||
Default: `2` | ||
#### `end: number` | ||
Target value. | ||
#### `prefix: string` | ||
Static text before the transitioning value. | ||
#### `redraw: boolean` | ||
Forces count up transition on every component update. | ||
Default: `false` | ||
#### `separator: string` | ||
Specifies character of thousands separator. | ||
#### `start: number` | ||
Initial value. | ||
Default: `0` | ||
#### `suffix: string` | ||
Static text after the transitioning value. | ||
#### `useEasing: boolean` | ||
Enables easing. Set to `false` for a linear transition. | ||
Default: `true` | ||
#### `easingFn: (t: number, b: number, c: number, d: number) => number` | ||
Easing function. Click [here](http://robertpenner.com/easing) for more details. | ||
Default: [`easeInExpo`](https://github.com/inorganik/countUp.js/blob/master/countUp.js#L103-L106) | ||
#### `formattingFn: (value: number) => string` | ||
Function to customize the formatting of the number | ||
#### `onEnd: ({ pauseResume, reset, start, update }) => void` | ||
Callback function on transition end. | ||
#### `onStart: ({ pauseResume, reset, update }) => void` | ||
Callback function on transition start. | ||
#### `onPauseResume: ({ reset, start, update }) => void` | ||
Callback function on pause or resume. | ||
#### `onReset: ({ pauseResume, start, update }) => void` | ||
Callback function on reset. | ||
#### `onUpdate: ({ pauseResume, reset, start }) => void` | ||
Callback function on update. | ||
### Render props | ||
#### `countUpRef: () => void` | ||
Ref to hook the countUp instance to | ||
#### `pauseResume: () => void` | ||
Pauses or resumes the transition | ||
#### `reset: () => void` | ||
Resets to initial value | ||
#### `start: () => void` | ||
Starts or restarts the transition | ||
#### `update: (newEnd: number?) => void` | ||
Updates transition to the new end value (if given) | ||
## Protips | ||
By default, the animation is triggered if any of the following props has changed: | ||
- `duration` | ||
@@ -137,25 +267,6 @@ - `end` | ||
You can set `redraw` to `true` If you want your component to always animate on every re-render. | ||
If `redraw` is set to `true` your component will start the transition on every component update. | ||
### Manually start the animation | ||
## License | ||
```js | ||
import React, { Component } from 'react'; | ||
import CountUp, { startAnimation } from 'react-countup'; | ||
const MyComponent = () => ( | ||
<div> | ||
<CountUp className="CountUp" start={0} end={100} duration={3} ref={(countUp) => { | ||
this.myCountUp = countUp; | ||
}} /> | ||
<button className="Button" onClick={(event) => { | ||
startAnimation(this.myCountUp); | ||
}}>Count me up!</button> | ||
</div> | ||
); | ||
export default App; | ||
``` | ||
## License | ||
MIT |
180
src/index.js
@@ -1,179 +0,1 @@ | ||
// @flow | ||
import React from 'react'; | ||
import Count from 'countup.js'; | ||
import type { Component } from 'react'; | ||
type Props = { | ||
className: string, | ||
decimal: string, | ||
decimals: number, | ||
duration: number, | ||
easingFn: () => void, | ||
end: number, | ||
formattingFn: (start: number) => string, | ||
onComplete: () => void, | ||
onStart: () => void, | ||
prefix: string, | ||
redraw: boolean, | ||
separator: string, | ||
start: number, | ||
style: {}, | ||
suffix: string, | ||
useEasing: boolean, | ||
}; | ||
type FormatNumberFn = ( | ||
start: number, | ||
options: { | ||
decimal: string, | ||
decimals: number, | ||
separator: string, | ||
prefix: string, | ||
suffix: string, | ||
}, | ||
) => string; | ||
// Adapted from the countup.js format number function | ||
// https://github.com/inorganik/countUp.js/blob/master/countUp.js#L46-L60 | ||
export const formatNumber: FormatNumberFn = (start, options) => { | ||
const neg = start < 0; | ||
const num = `${Math.abs(start).toFixed(options.decimals)}`; | ||
const x = num.split('.'); | ||
let x1 = x[0]; | ||
const x2 = x.length > 1 ? `${options.decimal}${x[1]}` : ''; | ||
const rgx = /(\d+)(\d{3})/; | ||
if (options.separator) { | ||
while (rgx.test(x1)) { | ||
x1 = x1.replace(rgx, `$1${options.separator}$2`); | ||
} | ||
} | ||
return `${neg ? '-' : ''}${options.prefix || ''}${x1}${x2}${options.suffix || | ||
''}`; | ||
}; | ||
export const startAnimation = (component: Component<*, *>) => { | ||
if (!(component && component.spanElement)) { | ||
throw new Error( | ||
'You need to pass the CountUp component as an argument!\neg. this.myCountUp.startAnimation(this.myCountUp);', | ||
); | ||
} | ||
const { | ||
decimal, | ||
decimals, | ||
duration, | ||
easingFn, | ||
end, | ||
formattingFn, | ||
onComplete, | ||
onStart, | ||
prefix, | ||
separator, | ||
start, | ||
suffix, | ||
useEasing, | ||
}: Props = component.props; | ||
const countupInstance = new Count( | ||
component.spanElement, | ||
start, | ||
end, | ||
decimals, | ||
duration, | ||
{ | ||
decimal, | ||
easingFn, | ||
formattingFn, | ||
separator, | ||
prefix, | ||
suffix, | ||
useEasing, | ||
useGrouping: !!separator, | ||
}, | ||
); | ||
if (typeof onStart === 'function') { | ||
onStart(); | ||
} | ||
countupInstance.start(onComplete); | ||
}; | ||
export default class CountUp extends React.Component<*, *> { | ||
static defaultProps = { | ||
className: undefined, | ||
decimal: '.', | ||
decimals: 0, | ||
duration: 3, | ||
easingFn: null, | ||
end: 100, | ||
formattingFn: null, | ||
onComplete: undefined, | ||
onStart: undefined, | ||
prefix: '', | ||
separator: '', | ||
start: 0, | ||
suffix: '', | ||
redraw: false, | ||
style: undefined, | ||
useEasing: true, | ||
}; | ||
componentDidMount() { | ||
startAnimation(this); | ||
} | ||
shouldComponentUpdate(nextProps: Props) { | ||
const hasCertainPropsChanged = | ||
this.props.duration !== nextProps.duration || | ||
this.props.end !== nextProps.end || | ||
this.props.start !== nextProps.start; | ||
return nextProps.redraw || hasCertainPropsChanged; | ||
} | ||
componentDidUpdate() { | ||
startAnimation(this); | ||
} | ||
spanElement = null; | ||
refSpan = (span: Element<*>) => { | ||
this.spanElement = span; | ||
}; | ||
refSpan: () => void; | ||
props: Props; | ||
render() { | ||
const { | ||
className, | ||
start, | ||
decimal, | ||
decimals, | ||
separator, | ||
prefix, | ||
suffix, | ||
style, | ||
formattingFn, | ||
} = this.props; | ||
return ( | ||
<span className={className} ref={this.refSpan} style={style}> | ||
{typeof formattingFn === 'function' | ||
? formattingFn(start) | ||
: formatNumber(start, { | ||
decimal, | ||
decimals, | ||
separator, | ||
prefix, | ||
suffix, | ||
})} | ||
</span> | ||
); | ||
} | ||
} | ||
export { default } from './CountUp'; |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
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
27922
8
481
271
4
24
2
1
1
+ Addedprop-types@^15.6.2
+ Addedwarning@^4.0.1
+ Addedreact@19.0.0(transitive)
+ Addedwarning@4.0.3(transitive)
- Removedreact@16.14.0(transitive)