diff --git a/README.md b/README.md index 2db7e0b..b32fc24 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,16 @@ # react-circle [![Build Status](https://travis-ci.org/zzarcon/react-circle.svg?branch=master)](https://travis-ci.org/zzarcon/react-circle) + > Renders a svg circle + percentage. It just works # Demo + [https://zzarcon.github.io/react-circle](https://zzarcon.github.io/react-circle/) + # Install 🚀 -``` +```bash $ yarn add react-circle ``` @@ -35,23 +38,23 @@ Optionally, you can pass the following props and customize it as your will ```javascript import Circle from 'react-circle'; -// All avaliable props for customization: -// Details are ordered as: -// : +// All avaliable props for customization(illustrated by default values): +// Details are ordered as: `: ` diff --git a/__tests__/__snapshots__/index.tsx.snap b/__tests__/__snapshots__/index.tsx.snap index 3023221..502d68b 100644 --- a/__tests__/__snapshots__/index.tsx.snap +++ b/__tests__/__snapshots__/index.tsx.snap @@ -3,13 +3,13 @@ exports[`ReactCircle Should default render with animation 1`] = ` Object { "strokeDashoffset": 825, - "transition": null, + "transition": undefined, } `; exports[`ReactCircle Should render without animation 1`] = ` Object { "strokeDashoffset": 825, - "transition": null, + "transition": undefined, } `; diff --git a/__tests__/index.tsx b/__tests__/index.tsx index 9187c51..19458dc 100644 --- a/__tests__/index.tsx +++ b/__tests__/index.tsx @@ -1,17 +1,25 @@ +/** + * @jest-environment node + */ + import * as React from 'react'; -import { shallow, render, mount } from 'enzyme'; +import { shallow, configure } from 'enzyme'; import Circle, {CircleProps} from '../src'; +const Adapter = require("enzyme-adapter-react-16"); + +configure({ adapter: new Adapter() }); + describe('ReactCircle', () => { const setup = (props?: Partial) => { const initialOptions = { progress: 25 } - + const circle = shallow( ); - + return { circle }; @@ -61,4 +69,30 @@ describe('ReactCircle', () => { const innerCircle = circle.find('circle').last() expect(innerCircle.prop('style')).toMatchSnapshot(); }) + + it('Should render with 1 second animation duration', () => { + const { circle } = setup(); + const innerCircle = circle.find('circle').last() + expect(innerCircle.prop('style').transition).toMatch(/1s/) + }) + + it('Should render with .25 second animation duration', () => { + const { circle } = setup({animationDuration:'.25s'}); + const innerCircle = circle.find('circle').last() + expect(innerCircle.prop('style').transition).toMatch(/.25s/) + }) + + it('Should call onAnimationEnd event handler', () => { + const onAnimationEnd = jest.fn(); + const { circle } = setup({onAnimationEnd}); + const innerCircle = circle.find('circle').last(); + innerCircle.simulate('transitionend'); + expect(onAnimationEnd).toBeCalled(); + }); + + it('Should render a full circle if progress is above 100%', () => { + const { circle } = setup({ progress: 120 }); + const innerCircle = circle.find('circle').last() + expect(innerCircle.prop('style').strokeDashoffset).toBe(0) + }); }); diff --git a/custom-typings/atlaskit.d.ts b/custom-typings/atlaskit.d.ts new file mode 100644 index 0000000..0f1c4ea --- /dev/null +++ b/custom-typings/atlaskit.d.ts @@ -0,0 +1 @@ +declare module '@atlaskit/*'; \ No newline at end of file diff --git a/example/app.tsx b/example/app.tsx index b18ceba..2049c77 100644 --- a/example/app.tsx +++ b/example/app.tsx @@ -84,14 +84,14 @@ export default class App extends Component<{}, AppState> { { - {!defaultMode ? + {!defaultMode ? { textColor={textColor} lineWidth={lineWidth} textStyle={{ font: 'bold 5rem Helvetica, Arial, sans-serif' }} + onAnimationEnd={() => { console.log('onAnimationEnd'); }} /> : } diff --git a/package.json b/package.json index a743551..c541ab6 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,13 @@ "@atlaskit/button": "^7.0.2", "@atlaskit/checkbox": "^2.0.0", "@atlaskit/field-text": "^4.3.0", + "enzyme": "^3.8.0", + "enzyme-adapter-react-16": "^1.9.1", "styled-components": "^3.2.3", "ts-react-toolbox": "^0.0.46" }, "engines": { - "node": "^8.4.0" + "node": ">=8.4.0" }, "scripts": { "dev": "ts-react-toolbox dev", @@ -24,10 +26,20 @@ "react": "^16.2.0" }, "name": "react-circle", - "version": "1.0.1", + "version": "1.1.1", + "license": "MIT", "main": "dist/index.js", "types": "dist/index.d.ts", "files": [ "dist" + ], + "repository": "https://github.com/zzarcon/react-circle", + "keywords": [ + "react", + "circle", + "svg", + "progress", + "react-circle", + "percentage" ] } diff --git a/src/circle.tsx b/src/circle.tsx index 2e4131a..2ceea1c 100644 --- a/src/circle.tsx +++ b/src/circle.tsx @@ -4,6 +4,7 @@ import { Component, CSSProperties } from 'react'; export interface CircleProps { progress: number; animate?: boolean; + animationDuration?: string; showPercentage?: boolean; showPercentageSymbol?: boolean; progressColor?: string; @@ -15,6 +16,7 @@ export interface CircleProps { textStyle?: CSSProperties; roundedStroke?: boolean; responsive?: boolean; + onAnimationEnd?(): void; } export interface CircleState { @@ -23,12 +25,13 @@ export interface CircleState { const radius = 175; const diameter = Math.round(Math.PI * radius * 2); -const getOffset = (val = 0) => Math.round((100 - val) / 100 * diameter); +const getOffset = (val = 0) => Math.round((100 - Math.min(val, 100)) / 100 * diameter); export class Circle extends Component { static defaultProps: CircleProps = { progress: 0, animate: true, + animationDuration: '1s', showPercentage: true, showPercentageSymbol: true, progressColor: 'rgb(76, 154, 255)', @@ -45,7 +48,7 @@ export class Circle extends Component { if (!showPercentage) return; return ( - + {progress}{showPercentageSymbol && %} ); @@ -53,16 +56,16 @@ export class Circle extends Component { render() { const { text } = this; - const { progress, size, bgColor, progressColor, lineWidth, animate, roundedStroke, responsive } = this.props; + const { progress, size, bgColor, progressColor, lineWidth, animate, animationDuration, roundedStroke, responsive, onAnimationEnd } = this.props; const strokeDashoffset = getOffset(progress); - const transition = animate ? 'stroke-dashoffset 1s ease-out' : null; + const transition = animate ? `stroke-dashoffset ${animationDuration} ease-out` : undefined; const strokeLinecap = roundedStroke ? 'round' : 'butt'; const svgSize = responsive ? '100%' : size; - + return ( - + {text} ); diff --git a/tsconfig.json b/tsconfig.json index 43a5ee6..bc97909 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,6 @@ "jsx": "react" }, "files": [ - "./typings/atlaskit.d.ts" + "./custom-typings/atlaskit.d.ts" ] } \ No newline at end of file