diff --git a/HISTORY.md b/HISTORY.md index ceeafcb..38da95e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,10 @@ --- +## 2.6.0 + +- Refactor to hooks. + ## 2.5.0 - Progress.Circle supports gradient color now. #73 diff --git a/README.md b/README.md index 7520949..b268cdf 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,10 @@ Progress Bar. [npm-image]: http://img.shields.io/npm/v/rc-progress.svg?style=flat-square [npm-url]: http://npmjs.org/package/rc-progress -[travis-image]: https://img.shields.io/travis/react-component/progress.svg?style=flat-square +[travis-image]: https://img.shields.io/travis/react-component/progress/master?style=flat-square [travis-url]: https://travis-ci.org/react-component/progress +[circleci-image]: https://img.shields.io/circleci/react-component/progress/master?style=flat-square +[circleci-url]: https://circleci.com/gh/react-component/progress [coveralls-image]: https://img.shields.io/coveralls/react-component/progress.svg?style=flat-square [coveralls-url]: https://coveralls.io/r/react-component/progress?branch=master [david-url]: https://david-dm.org/react-component/progress @@ -43,15 +45,23 @@ http://react-component.github.io/progress/ ## Usage -```jsx +```js import { Line, Circle } from 'rc-progress'; -ReactDOM.render(
- - -
, container); +export default () => ( + <> + + + +); ``` +## Compatibility + +| [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Electron](http://godban.github.io/browsers-support-badges/)
Electron | +| --- | --- | --- | --- | --- | +| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + ## API ### props diff --git a/package.json b/package.json index bde0712..b80249d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-progress", - "version": "2.5.3", + "version": "2.6.0", "description": "progress ui component for react", "keywords": [ "react", @@ -9,7 +9,6 @@ "progress" ], "homepage": "http://github.com/react-component/progress", - "author": "tsjxyz@gmail.com", "repository": { "type": "git", "url": "git@github.com:react-component/progress.git" @@ -17,7 +16,7 @@ "bugs": { "url": "http://github.com/react-component/progress/issues" }, - "licenses": "MIT", + "license": "MIT", "main": "lib/index", "module": "es/index", "types": "./typings/index.d.ts", @@ -42,8 +41,8 @@ "build": "rc-tools run build", "gh-pages": "rc-tools run gh-pages", "start": "rc-tools run server", - "compile": "rc-tools run compile --babel-runtime", - "pub": "rc-tools run pub --babel-runtime", + "compile": "rc-tools run compile", + "pub": "rc-tools run pub", "lint": "rc-tools run lint", "lint:fix": "rc-tools run lint --fix", "prettier": "rc-tools run prettier", @@ -69,7 +68,6 @@ ] }, "dependencies": { - "babel-runtime": "6.x", - "prop-types": "^15.5.8" + "classnames": "^2.2.6" } } diff --git a/src/Circle.js b/src/Circle.js index 783604f..0ac2743 100644 --- a/src/Circle.js +++ b/src/Circle.js @@ -1,8 +1,7 @@ /* eslint react/prop-types: 0 */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import enhancer from './enhancer'; -import { propTypes, defaultProps } from './types'; +import React, { useMemo } from 'react'; +import classNames from 'classnames'; +import { useTransitionDuration, defaultProps } from './common'; let gradientSeed = 0; @@ -58,142 +57,105 @@ function getPathStyles(offset, percent, strokeColor, strokeWidth, gapDegree = 0, }; } -class Circle extends Component { - paths = {}; - - gradientId = 0; - - constructor() { - super(); - this.gradientId = gradientSeed; +const Circle = ({ + prefixCls, + strokeWidth, + trailWidth, + gapDegree, + gapPosition, + trailColor, + strokeLinecap, + style, + className, + strokeColor, + percent, + ...restProps +}) => { + const gradientId = useMemo(() => { gradientSeed += 1; - } - - getStokeList() { - const { - prefixCls, - percent, - strokeColor, - strokeWidth, - strokeLinecap, - gapDegree, - gapPosition, - } = this.props; - const percentList = toArray(percent); - const strokeColorList = toArray(strokeColor); - + return gradientSeed; + }, []); + const { pathString, pathStyle } = getPathStyles( + 0, + 100, + trailColor, + strokeWidth, + gapDegree, + gapPosition, + ); + const percentList = toArray(percent); + const strokeColorList = toArray(strokeColor); + const gradient = strokeColorList.find( + color => Object.prototype.toString.call(color) === '[object Object]', + ); + + const [paths] = useTransitionDuration(percentList); + + const getStokeList = () => { let stackPtg = 0; return percentList.map((ptg, index) => { const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1]; const stroke = Object.prototype.toString.call(color) === '[object Object]' - ? `url(#${prefixCls}-gradient-${this.gradientId})` + ? `url(#${prefixCls}-gradient-${gradientId})` : ''; - const { pathString, pathStyle } = getPathStyles( - stackPtg, - ptg, - color, - strokeWidth, - gapDegree, - gapPosition, - ); - + const pathStyles = getPathStyles(stackPtg, ptg, color, strokeWidth, gapDegree, gapPosition); stackPtg += ptg; - return ( { - this.paths[index] = path; - }} + style={pathStyles.pathStyle} + ref={paths[index]} /> ); }); - } - - render() { - const { - prefixCls, - strokeWidth, - trailWidth, - gapDegree, - gapPosition, - trailColor, - strokeLinecap, - style, - className, - strokeColor, - ...restProps - } = this.props; - const { pathString, pathStyle } = getPathStyles( - 0, - 100, - trailColor, - strokeWidth, - gapDegree, - gapPosition, - ); - delete restProps.percent; - const strokeColorList = toArray(strokeColor); - const gradient = strokeColorList.find( - color => Object.prototype.toString.call(color) === '[object Object]', - ); - - return ( - - {gradient && ( - - - {Object.keys(gradient) - .sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b)) - .map((key, index) => ( - - ))} - - - )} - - {this.getStokeList().reverse()} - - ); - } -} + }; -Circle.propTypes = { - ...propTypes, - gapPosition: PropTypes.oneOf(['top', 'bottom', 'left', 'right']), + return ( + + {gradient && ( + + + {Object.keys(gradient) + .sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b)) + .map((key, index) => ( + + ))} + + + )} + + {getStokeList().reverse()} + + ); }; -Circle.defaultProps = { - ...defaultProps, - gapPosition: 'top', -}; +Circle.defaultProps = defaultProps; -export default enhancer(Circle); +export default Circle; diff --git a/src/Line.js b/src/Line.js index d310ddc..2a75703 100644 --- a/src/Line.js +++ b/src/Line.js @@ -1,89 +1,77 @@ -import React, { Component } from 'react'; -import enhancer from './enhancer'; -import { propTypes, defaultProps } from './types'; +/* eslint react/prop-types: 0 */ +import React from 'react'; +import classNames from 'classnames'; +import { useTransitionDuration, defaultProps } from './common'; -class Line extends Component { - paths = {}; +const Line = ({ + className, + percent, + prefixCls, + strokeColor, + strokeLinecap, + strokeWidth, + style, + trailColor, + trailWidth, + transition, + ...restProps +}) => { + delete restProps.gapPosition; + const percentList = Array.isArray(percent) ? percent : [percent]; + const strokeColorList = Array.isArray(strokeColor) ? strokeColor : [strokeColor]; - render() { - const { - className, - percent, - prefixCls, - strokeColor, - strokeLinecap, - strokeWidth, - style, - trailColor, - trailWidth, - transition, - ...restProps - } = this.props; + const [paths] = useTransitionDuration(percentList); - delete restProps.gapPosition; - - const percentList = Array.isArray(percent) ? percent : [percent]; - const strokeColorList = Array.isArray(strokeColor) ? strokeColor : [strokeColor]; - - const center = strokeWidth / 2; - const right = 100 - strokeWidth / 2; - const pathString = `M ${strokeLinecap === 'round' ? center : 0},${center} - L ${strokeLinecap === 'round' ? right : 100},${center}`; - const viewBoxString = `0 0 100 ${strokeWidth}`; - - let stackPtg = 0; - - return ( - - - {percentList.map((ptg, index) => { - const pathStyle = { - strokeDasharray: `${ptg}px, 100px`, - strokeDashoffset: `-${stackPtg}px`, - transition: - transition || - 'stroke-dashoffset 0.3s ease 0s, stroke-dasharray .3s ease 0s, stroke 0.3s linear', - }; - const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1]; - - stackPtg += ptg; - - return ( - { - this.paths[index] = path; - }} - style={pathStyle} - /> - ); - })} - - ); - } -} - -Line.propTypes = propTypes; + const center = strokeWidth / 2; + const right = 100 - strokeWidth / 2; + const pathString = `M ${strokeLinecap === 'round' ? center : 0},${center} + L ${strokeLinecap === 'round' ? right : 100},${center}`; + const viewBoxString = `0 0 100 ${strokeWidth}`; + let stackPtg = 0; + return ( + + + {percentList.map((ptg, index) => { + const pathStyle = { + strokeDasharray: `${ptg}px, 100px`, + strokeDashoffset: `-${stackPtg}px`, + transition: + transition || + 'stroke-dashoffset 0.3s ease 0s, stroke-dasharray .3s ease 0s, stroke 0.3s linear', + }; + const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1]; + stackPtg += ptg; + return ( + + ); + })} + + ); +}; Line.defaultProps = defaultProps; -export default enhancer(Line); +export default Line; diff --git a/src/common.js b/src/common.js new file mode 100644 index 0000000..8ac8362 --- /dev/null +++ b/src/common.js @@ -0,0 +1,42 @@ +import { useRef, useEffect } from 'react'; + +export const defaultProps = { + className: '', + percent: 0, + prefixCls: 'rc-progress', + strokeColor: '#2db7f5', + strokeLinecap: 'round', + strokeWidth: 1, + style: {}, + trailColor: '#D9D9D9', + trailWidth: 1, +}; + +export const useTransitionDuration = percentList => { + const paths = percentList.map(() => useRef()); + const prevTimeStamp = useRef(); + useEffect(() => { + const now = Date.now(); + let updated = false; + + Object.keys(paths).forEach(key => { + const path = paths[key].current; + if (!path) { + return; + } + updated = true; + const pathStyle = path.style; + pathStyle.transitionDuration = '.3s, .3s, .3s, .06s'; + + if (prevTimeStamp.current && now - prevTimeStamp.current < 100) { + pathStyle.transitionDuration = '0s, 0s'; + } + }); + + if (updated) { + prevTimeStamp.current = Date.now(); + } + }); + + return [paths]; +}; diff --git a/src/enhancer.js b/src/enhancer.js deleted file mode 100644 index 97cef8b..0000000 --- a/src/enhancer.js +++ /dev/null @@ -1,33 +0,0 @@ -const enhancer = WrappedComponent => - class Progress extends WrappedComponent { - componentDidUpdate() { - const now = Date.now(); - let updated = false; - - Object.keys(this.paths).forEach(key => { - const path = this.paths[key]; - - if (!path) { - return; - } - - updated = true; - const pathStyle = path.style; - pathStyle.transitionDuration = '.3s, .3s, .3s, .06s'; - - if (this.prevTimeStamp && now - this.prevTimeStamp < 100) { - pathStyle.transitionDuration = '0s, 0s'; - } - }); - - if (updated) { - this.prevTimeStamp = Date.now(); - } - } - - render() { - return super.render(); - } - }; - -export default enhancer; diff --git a/src/types.js b/src/types.js deleted file mode 100644 index 75297e1..0000000 --- a/src/types.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; - -export const defaultProps = { - className: '', - percent: 0, - prefixCls: 'rc-progress', - strokeColor: '#2db7f5', - strokeLinecap: 'round', - strokeWidth: 1, - style: {}, - trailColor: '#D9D9D9', - trailWidth: 1, -}; - -const mixedType = PropTypes.oneOfType([PropTypes.number, PropTypes.string]); - -export const propTypes = { - className: PropTypes.string, - percent: PropTypes.oneOfType([mixedType, PropTypes.arrayOf(mixedType)]), - prefixCls: PropTypes.string, - strokeColor: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])), - PropTypes.object, - ]), - strokeLinecap: PropTypes.oneOf(['butt', 'round', 'square']), - strokeWidth: mixedType, - style: PropTypes.object, - trailColor: PropTypes.string, - trailWidth: mixedType, -}; diff --git a/tests/index.spec.js b/tests/index.spec.js index 7950839..4640e35 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -20,50 +20,27 @@ describe('Progress', () => { }); describe('Line', () => { - it('works', () => { - const line = ReactDOM.render(, div); - expect(line.props.percent).toBe('30'); + it('change with animation', () => { + class Demo extends React.Component { + state = { + percent: '0', + }; + + render() { + const { percent } = this.state; + return ; + } + } + const line = ReactDOM.render(, div); + expect(line.state.percent).toBe('0'); + line.setState({ + percent: '30', + }); + expect(line.state.percent).toBe('30'); }); }); describe('Circle', () => { - it('works', () => { - const circle = ReactDOM.render(, div); - expect(circle.props.percent).toBe('30'); - }); - - it('gap degree bottom', () => { - const circle = ReactDOM.render( - , - div, - ); - expect(circle.props.percent).toBe('30'); - }); - - it('gap degree top', () => { - const circle = ReactDOM.render( - , - div, - ); - expect(circle.props.percent).toBe('30'); - }); - - it('gap degree left', () => { - const circle = ReactDOM.render( - , - div, - ); - expect(circle.props.percent).toBe('30'); - }); - - it('gap degree right', () => { - const circle = ReactDOM.render( - , - div, - ); - expect(circle.props.percent).toBe('30'); - }); - it('change with animation', () => { class Demo extends React.Component { state = {