@rc-component/progress 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +163 -0
- package/es/Circle/PtgCircle.d.ts +18 -0
- package/es/Circle/PtgCircle.js +79 -0
- package/es/Circle/index.d.ts +4 -0
- package/es/Circle/index.js +153 -0
- package/es/Circle/util.d.ts +5 -0
- package/es/Circle/util.js +30 -0
- package/es/Line.d.ts +4 -0
- package/es/Line.js +105 -0
- package/es/common.d.ts +3 -0
- package/es/common.js +35 -0
- package/es/index.d.ts +4 -0
- package/es/index.js +3 -0
- package/es/interface.d.ts +30 -0
- package/es/interface.js +1 -0
- package/es/utils/getIndeterminateCircle.d.ts +19 -0
- package/es/utils/getIndeterminateCircle.js +23 -0
- package/es/utils/getIndeterminateLine.d.ts +25 -0
- package/es/utils/getIndeterminateLine.js +29 -0
- package/lib/Circle/PtgCircle.d.ts +18 -0
- package/lib/Circle/PtgCircle.js +88 -0
- package/lib/Circle/index.d.ts +4 -0
- package/lib/Circle/index.js +162 -0
- package/lib/Circle/util.d.ts +5 -0
- package/lib/Circle/util.js +37 -0
- package/lib/Line.d.ts +4 -0
- package/lib/Line.js +114 -0
- package/lib/common.d.ts +3 -0
- package/lib/common.js +42 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +20 -0
- package/lib/interface.d.ts +30 -0
- package/lib/interface.js +5 -0
- package/lib/utils/getIndeterminateCircle.d.ts +19 -0
- package/lib/utils/getIndeterminateCircle.js +31 -0
- package/lib/utils/getIndeterminateLine.d.ts +25 -0
- package/lib/utils/getIndeterminateLine.js +37 -0
- package/package.json +73 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014-present yiminghe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @rc-component/progress
|
|
2
|
+
|
|
3
|
+
Progress Bar.
|
|
4
|
+
|
|
5
|
+
[![NPM version][npm-image]][npm-url] [](https://github.com/umijs/dumi) [![build status][github-actions-image]][github-actions-url] [![Test coverage][coveralls-image]][coveralls-url] [![npm download][download-image]][download-url] [![bundle size][bundlephobia-image]][bundlephobia-url]
|
|
6
|
+
|
|
7
|
+
[npm-image]: http://img.shields.io/npm/v/@rc-component/progress.svg?style=flat-square
|
|
8
|
+
[npm-url]: http://npmjs.org/package/@rc-component/progress
|
|
9
|
+
[github-actions-image]: https://github.com/react-component/progress/workflows/CI/badge.svg
|
|
10
|
+
[github-actions-url]: https://github.com/react-component/progress/actions
|
|
11
|
+
[circleci-image]: https://img.shields.io/circleci/react-component/progress/master?style=flat-square
|
|
12
|
+
[circleci-url]: https://circleci.com/gh/react-component/progress
|
|
13
|
+
[coveralls-image]: https://img.shields.io/coveralls/react-component/progress.svg?style=flat-square
|
|
14
|
+
[coveralls-url]: https://coveralls.io/r/react-component/progress?branch=master
|
|
15
|
+
[david-url]: https://david-dm.org/react-component/progress
|
|
16
|
+
[david-image]: https://david-dm.org/react-component/progress/status.svg?style=flat-square
|
|
17
|
+
[david-dev-url]: https://david-dm.org/react-component/progress?type=dev
|
|
18
|
+
[david-dev-image]: https://david-dm.org/react-component/progress/dev-status.svg?style=flat-square
|
|
19
|
+
[download-image]: https://img.shields.io/npm/dm/@rc-component/progress.svg?style=flat-square
|
|
20
|
+
[download-url]: https://npmjs.org/package/@rc-component/progress
|
|
21
|
+
[bundlephobia-url]: https://bundlephobia.com/result?p=@rc-component/progress
|
|
22
|
+
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/@rc-component/progress
|
|
23
|
+
|
|
24
|
+
## Example
|
|
25
|
+
|
|
26
|
+
https://progress.react-component.vercel.app/
|
|
27
|
+
|
|
28
|
+
## Screenshots
|
|
29
|
+
|
|
30
|
+
<img src="https://t.alipayobjects.com/images/T12p8gXjpgXXXXXXXX.gif" />
|
|
31
|
+
|
|
32
|
+
## Browsers
|
|
33
|
+
|
|
34
|
+
* support IE9+, Chrome, Firefox, Safari
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
[](https://npmjs.org/package/@rc-component/progress)
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
import { Line, Circle } from '@rc-component/progress';
|
|
44
|
+
|
|
45
|
+
export default () => (
|
|
46
|
+
<>
|
|
47
|
+
<Line percent={10} strokeWidth={4} strokeColor="#D3D3D3" />
|
|
48
|
+
<Circle percent={10} strokeWidth={4} strokeColor="#D3D3D3" />
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Compatibility
|
|
54
|
+
|
|
55
|
+
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Electron |
|
|
56
|
+
| --- | --- | --- | --- | --- |
|
|
57
|
+
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
### props
|
|
62
|
+
|
|
63
|
+
<table class="table table-bordered table-striped">
|
|
64
|
+
<thead>
|
|
65
|
+
<tr>
|
|
66
|
+
<th style="width: 100px;">name</th>
|
|
67
|
+
<th style="width: 50px;">type</th>
|
|
68
|
+
<th style="width: 50px;">default</th>
|
|
69
|
+
<th>description</th>
|
|
70
|
+
</tr>
|
|
71
|
+
</thead>
|
|
72
|
+
<tbody>
|
|
73
|
+
<tr>
|
|
74
|
+
<td>strokeWidth</td>
|
|
75
|
+
<td>Number</td>
|
|
76
|
+
<td>1</td>
|
|
77
|
+
<td>Width of the stroke. Unit is percentage of SVG canvas size.</td>
|
|
78
|
+
</tr>
|
|
79
|
+
<tr>
|
|
80
|
+
<td>strokeColor</td>
|
|
81
|
+
<td>String</td>
|
|
82
|
+
<td>#2db7f5</td>
|
|
83
|
+
<td>Stroke color.</td>
|
|
84
|
+
</tr>
|
|
85
|
+
<tr>
|
|
86
|
+
<td>trailWidth</td>
|
|
87
|
+
<td>Number</td>
|
|
88
|
+
<td>1</td>
|
|
89
|
+
<td>Width of the trail stroke. Unit is percentage of SVG canvas size. Trail is always centered relative to actual progress path. If trailWidth is not defined, it is the same as strokeWidth.</td>
|
|
90
|
+
</tr>
|
|
91
|
+
<tr>
|
|
92
|
+
<td>trailColor</td>
|
|
93
|
+
<td>String</td>
|
|
94
|
+
<td>#D9D9D9</td>
|
|
95
|
+
<td>Color for lighter trail stroke underneath the actual progress path.</td>
|
|
96
|
+
</tr>
|
|
97
|
+
<tr>
|
|
98
|
+
<td>strokeLinecap</td>
|
|
99
|
+
<td>String</td>
|
|
100
|
+
<td>'round'</td>
|
|
101
|
+
<td>The shape to be used at the end of the progress bar: can be `butt`, `square` or `round`.</td>
|
|
102
|
+
</tr>
|
|
103
|
+
<tr>
|
|
104
|
+
<td>prefixCls</td>
|
|
105
|
+
<td>String</td>
|
|
106
|
+
<td>rc-progress</td>
|
|
107
|
+
<td>prefix className for component</td>
|
|
108
|
+
</tr>
|
|
109
|
+
<tr>
|
|
110
|
+
<td>className</td>
|
|
111
|
+
<td>String</td>
|
|
112
|
+
<td></td>
|
|
113
|
+
<td>customized className</td>
|
|
114
|
+
</tr>
|
|
115
|
+
<tr>
|
|
116
|
+
<td>style</td>
|
|
117
|
+
<td>Object</td>
|
|
118
|
+
<td></td>
|
|
119
|
+
<td>style object will be added to svg element</td>
|
|
120
|
+
</tr>
|
|
121
|
+
<tr>
|
|
122
|
+
<td>percent</td>
|
|
123
|
+
<td>Number | Number[]</td>
|
|
124
|
+
<td>0</td>
|
|
125
|
+
<td>the percent of the progress</td>
|
|
126
|
+
</tr>
|
|
127
|
+
<tr>
|
|
128
|
+
<td>gapDegree</td>
|
|
129
|
+
<td>Number</td>
|
|
130
|
+
<td>0</td>
|
|
131
|
+
<td>the gap degree of half circle, 0 - 360</td>
|
|
132
|
+
</tr>
|
|
133
|
+
<tr>
|
|
134
|
+
<td>gapPosition</td>
|
|
135
|
+
<td>String</td>
|
|
136
|
+
<td>top</td>
|
|
137
|
+
<td>the gap position: can be `top`, `bottom`, `left`, or `right`. </td>
|
|
138
|
+
</tr>
|
|
139
|
+
<tr>
|
|
140
|
+
<td>loading</td>
|
|
141
|
+
<td>Boolean</td>
|
|
142
|
+
<td>false</td>
|
|
143
|
+
<td>If it is true the indeterminate progress will be enabled.</td>
|
|
144
|
+
</tr>
|
|
145
|
+
</tbody>
|
|
146
|
+
</table>
|
|
147
|
+
|
|
148
|
+
## Installation
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
npm install --save @rc-component/progress
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Development
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
npm install
|
|
158
|
+
npm start
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
@rc-component/progress is released under the MIT license.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { ProgressProps } from '..';
|
|
3
|
+
import type { StrokeColorObject } from '../interface';
|
|
4
|
+
export interface ColorGradientProps {
|
|
5
|
+
prefixCls: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
gradientId: string;
|
|
8
|
+
style: React.CSSProperties;
|
|
9
|
+
ptg: number;
|
|
10
|
+
radius: number;
|
|
11
|
+
strokeLinecap: ProgressProps['strokeLinecap'];
|
|
12
|
+
strokeWidth: ProgressProps['strokeWidth'];
|
|
13
|
+
size: number;
|
|
14
|
+
color: string | StrokeColorObject;
|
|
15
|
+
gapDegree: number;
|
|
16
|
+
}
|
|
17
|
+
declare const PtgCircle: React.ForwardRefExoticComponent<ColorGradientProps & React.RefAttributes<SVGCircleElement>>;
|
|
18
|
+
export default PtgCircle;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
const Block = ({
|
|
4
|
+
bg,
|
|
5
|
+
children
|
|
6
|
+
}) => /*#__PURE__*/React.createElement("div", {
|
|
7
|
+
style: {
|
|
8
|
+
width: '100%',
|
|
9
|
+
height: '100%',
|
|
10
|
+
background: bg
|
|
11
|
+
}
|
|
12
|
+
}, children);
|
|
13
|
+
function getPtgColors(color, scale) {
|
|
14
|
+
return Object.keys(color).map(key => {
|
|
15
|
+
const parsedKey = parseFloat(key);
|
|
16
|
+
const ptgKey = `${Math.floor(parsedKey * scale)}%`;
|
|
17
|
+
return `${color[key]} ${ptgKey}`;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const PtgCircle = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
21
|
+
const {
|
|
22
|
+
prefixCls,
|
|
23
|
+
color,
|
|
24
|
+
gradientId,
|
|
25
|
+
radius,
|
|
26
|
+
className,
|
|
27
|
+
style: circleStyleForStack,
|
|
28
|
+
ptg,
|
|
29
|
+
strokeLinecap,
|
|
30
|
+
strokeWidth,
|
|
31
|
+
size,
|
|
32
|
+
gapDegree
|
|
33
|
+
} = props;
|
|
34
|
+
const isGradient = color && typeof color === 'object';
|
|
35
|
+
const stroke = isGradient ? `#FFF` : undefined;
|
|
36
|
+
|
|
37
|
+
// ========================== Circle ==========================
|
|
38
|
+
const halfSize = size / 2;
|
|
39
|
+
const circleNode = /*#__PURE__*/React.createElement("circle", {
|
|
40
|
+
className: classNames(`${prefixCls}-circle-path`, className),
|
|
41
|
+
r: radius,
|
|
42
|
+
cx: halfSize,
|
|
43
|
+
cy: halfSize,
|
|
44
|
+
stroke: stroke,
|
|
45
|
+
strokeLinecap: strokeLinecap,
|
|
46
|
+
strokeWidth: strokeWidth,
|
|
47
|
+
opacity: ptg === 0 ? 0 : 1,
|
|
48
|
+
style: circleStyleForStack,
|
|
49
|
+
ref: ref
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// ========================== Render ==========================
|
|
53
|
+
if (!isGradient) {
|
|
54
|
+
return circleNode;
|
|
55
|
+
}
|
|
56
|
+
const maskId = `${gradientId}-conic`;
|
|
57
|
+
const fromDeg = gapDegree ? `${180 + gapDegree / 2}deg` : '0deg';
|
|
58
|
+
const conicColors = getPtgColors(color, (360 - gapDegree) / 360);
|
|
59
|
+
const linearColors = getPtgColors(color, 1);
|
|
60
|
+
const conicColorBg = `conic-gradient(from ${fromDeg}, ${conicColors.join(', ')})`;
|
|
61
|
+
const linearColorBg = `linear-gradient(to ${gapDegree ? 'bottom' : 'top'}, ${linearColors.join(', ')})`;
|
|
62
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("mask", {
|
|
63
|
+
id: maskId
|
|
64
|
+
}, circleNode), /*#__PURE__*/React.createElement("foreignObject", {
|
|
65
|
+
x: 0,
|
|
66
|
+
y: 0,
|
|
67
|
+
width: size,
|
|
68
|
+
height: size,
|
|
69
|
+
mask: `url(#${maskId})`
|
|
70
|
+
}, /*#__PURE__*/React.createElement(Block, {
|
|
71
|
+
bg: linearColorBg
|
|
72
|
+
}, /*#__PURE__*/React.createElement(Block, {
|
|
73
|
+
bg: conicColorBg
|
|
74
|
+
}))));
|
|
75
|
+
});
|
|
76
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
77
|
+
PtgCircle.displayName = 'PtgCircle';
|
|
78
|
+
}
|
|
79
|
+
export default PtgCircle;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import cls from 'classnames';
|
|
4
|
+
import { defaultProps, useTransitionDuration } from "../common";
|
|
5
|
+
import useId from "@rc-component/util/es/hooks/useId";
|
|
6
|
+
import PtgCircle from "./PtgCircle";
|
|
7
|
+
import { VIEW_BOX_SIZE, getCircleStyle } from "./util";
|
|
8
|
+
import getIndeterminateCircle from "../utils/getIndeterminateCircle";
|
|
9
|
+
function toArray(value) {
|
|
10
|
+
const mergedValue = value ?? [];
|
|
11
|
+
return Array.isArray(mergedValue) ? mergedValue : [mergedValue];
|
|
12
|
+
}
|
|
13
|
+
const Circle = props => {
|
|
14
|
+
const {
|
|
15
|
+
id,
|
|
16
|
+
prefixCls,
|
|
17
|
+
classNames = {},
|
|
18
|
+
styles = {},
|
|
19
|
+
steps,
|
|
20
|
+
strokeWidth,
|
|
21
|
+
trailWidth,
|
|
22
|
+
gapDegree = 0,
|
|
23
|
+
gapPosition,
|
|
24
|
+
trailColor,
|
|
25
|
+
strokeLinecap,
|
|
26
|
+
style,
|
|
27
|
+
className,
|
|
28
|
+
strokeColor,
|
|
29
|
+
percent,
|
|
30
|
+
loading,
|
|
31
|
+
...restProps
|
|
32
|
+
} = {
|
|
33
|
+
...defaultProps,
|
|
34
|
+
...props
|
|
35
|
+
};
|
|
36
|
+
const halfSize = VIEW_BOX_SIZE / 2;
|
|
37
|
+
const mergedId = useId(id);
|
|
38
|
+
const gradientId = `${mergedId}-gradient`;
|
|
39
|
+
const radius = halfSize - strokeWidth / 2;
|
|
40
|
+
const perimeter = Math.PI * 2 * radius;
|
|
41
|
+
const rotateDeg = gapDegree > 0 ? 90 + gapDegree / 2 : -90;
|
|
42
|
+
const perimeterWithoutGap = perimeter * ((360 - gapDegree) / 360);
|
|
43
|
+
const {
|
|
44
|
+
count: stepCount,
|
|
45
|
+
gap: stepGap
|
|
46
|
+
} = typeof steps === 'object' ? steps : {
|
|
47
|
+
count: steps,
|
|
48
|
+
gap: 2
|
|
49
|
+
};
|
|
50
|
+
const percentList = toArray(percent);
|
|
51
|
+
const strokeColorList = toArray(strokeColor);
|
|
52
|
+
const gradient = strokeColorList.find(color => color && typeof color === 'object');
|
|
53
|
+
const isConicGradient = gradient && typeof gradient === 'object';
|
|
54
|
+
const mergedStrokeLinecap = isConicGradient ? 'butt' : strokeLinecap;
|
|
55
|
+
const {
|
|
56
|
+
indeterminateStyleProps,
|
|
57
|
+
indeterminateStyleAnimation
|
|
58
|
+
} = getIndeterminateCircle({
|
|
59
|
+
id: mergedId,
|
|
60
|
+
loading
|
|
61
|
+
});
|
|
62
|
+
const circleStyle = getCircleStyle(perimeter, perimeterWithoutGap, 0, 100, rotateDeg, gapDegree, gapPosition, trailColor, mergedStrokeLinecap, strokeWidth);
|
|
63
|
+
const paths = useTransitionDuration();
|
|
64
|
+
const getStokeList = () => {
|
|
65
|
+
let stackPtg = 0;
|
|
66
|
+
return percentList.map((ptg, index) => {
|
|
67
|
+
const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1];
|
|
68
|
+
const circleStyleForStack = getCircleStyle(perimeter, perimeterWithoutGap, stackPtg, ptg, rotateDeg, gapDegree, gapPosition, color, mergedStrokeLinecap, strokeWidth);
|
|
69
|
+
stackPtg += ptg;
|
|
70
|
+
return /*#__PURE__*/React.createElement(PtgCircle, {
|
|
71
|
+
key: index,
|
|
72
|
+
color: color,
|
|
73
|
+
ptg: ptg,
|
|
74
|
+
radius: radius,
|
|
75
|
+
prefixCls: prefixCls,
|
|
76
|
+
gradientId: gradientId,
|
|
77
|
+
className: classNames.track,
|
|
78
|
+
style: {
|
|
79
|
+
...circleStyleForStack,
|
|
80
|
+
...indeterminateStyleProps,
|
|
81
|
+
...styles.track
|
|
82
|
+
},
|
|
83
|
+
strokeLinecap: mergedStrokeLinecap,
|
|
84
|
+
strokeWidth: strokeWidth,
|
|
85
|
+
gapDegree: gapDegree,
|
|
86
|
+
ref: elem => {
|
|
87
|
+
// https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
|
|
88
|
+
// React will call the ref callback with the DOM element when the component mounts,
|
|
89
|
+
// and call it with `null` when it unmounts.
|
|
90
|
+
// Refs are guaranteed to be up-to-date before componentDidMount or componentDidUpdate fires.
|
|
91
|
+
|
|
92
|
+
paths[index] = elem;
|
|
93
|
+
},
|
|
94
|
+
size: VIEW_BOX_SIZE
|
|
95
|
+
});
|
|
96
|
+
}).reverse();
|
|
97
|
+
};
|
|
98
|
+
const getStepStokeList = () => {
|
|
99
|
+
// only show the first percent when pass steps
|
|
100
|
+
const current = Math.round(stepCount * (percentList[0] / 100));
|
|
101
|
+
const stepPtg = 100 / stepCount;
|
|
102
|
+
let stackPtg = 0;
|
|
103
|
+
return new Array(stepCount).fill(null).map((_, index) => {
|
|
104
|
+
const color = index <= current - 1 ? strokeColorList[0] : trailColor;
|
|
105
|
+
const stroke = color && typeof color === 'object' ? `url(#${gradientId})` : undefined;
|
|
106
|
+
const circleStyleForStack = getCircleStyle(perimeter, perimeterWithoutGap, stackPtg, stepPtg, rotateDeg, gapDegree, gapPosition, color, 'butt', strokeWidth, stepGap);
|
|
107
|
+
stackPtg += (perimeterWithoutGap - circleStyleForStack.strokeDashoffset + stepGap) * 100 / perimeterWithoutGap;
|
|
108
|
+
return /*#__PURE__*/React.createElement("circle", {
|
|
109
|
+
key: index,
|
|
110
|
+
className: cls(`${prefixCls}-circle-path`, classNames.track),
|
|
111
|
+
r: radius,
|
|
112
|
+
cx: halfSize,
|
|
113
|
+
cy: halfSize,
|
|
114
|
+
stroke: stroke,
|
|
115
|
+
strokeWidth: strokeWidth,
|
|
116
|
+
opacity: 1,
|
|
117
|
+
style: {
|
|
118
|
+
...circleStyleForStack,
|
|
119
|
+
...styles.track
|
|
120
|
+
},
|
|
121
|
+
ref: elem => {
|
|
122
|
+
paths[index] = elem;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
return /*#__PURE__*/React.createElement("svg", _extends({
|
|
128
|
+
className: cls(`${prefixCls}-circle`, classNames.root, className),
|
|
129
|
+
viewBox: `0 0 ${VIEW_BOX_SIZE} ${VIEW_BOX_SIZE}`,
|
|
130
|
+
style: {
|
|
131
|
+
...styles.root,
|
|
132
|
+
...style
|
|
133
|
+
},
|
|
134
|
+
id: id,
|
|
135
|
+
role: "presentation"
|
|
136
|
+
}, restProps), !stepCount && /*#__PURE__*/React.createElement("circle", {
|
|
137
|
+
className: cls(`${prefixCls}-circle-trail`, classNames.rail),
|
|
138
|
+
r: radius,
|
|
139
|
+
cx: halfSize,
|
|
140
|
+
cy: halfSize,
|
|
141
|
+
stroke: trailColor,
|
|
142
|
+
strokeLinecap: mergedStrokeLinecap,
|
|
143
|
+
strokeWidth: trailWidth || strokeWidth,
|
|
144
|
+
style: {
|
|
145
|
+
...circleStyle,
|
|
146
|
+
...styles.rail
|
|
147
|
+
}
|
|
148
|
+
}), stepCount ? getStepStokeList() : getStokeList(), indeterminateStyleAnimation);
|
|
149
|
+
};
|
|
150
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
151
|
+
Circle.displayName = 'Circle';
|
|
152
|
+
}
|
|
153
|
+
export default Circle;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { StrokeColorType } from '../interface';
|
|
2
|
+
import type { ProgressProps } from '..';
|
|
3
|
+
import type React from 'react';
|
|
4
|
+
export declare const VIEW_BOX_SIZE = 100;
|
|
5
|
+
export declare const getCircleStyle: (perimeter: number, perimeterWithoutGap: number, offset: number, percent: number, rotateDeg: number, gapDegree: number, gapPosition: ProgressProps['gapPosition'] | undefined, strokeColor: StrokeColorType, strokeLinecap: ProgressProps['strokeLinecap'], strokeWidth: number, stepSpace?: number) => React.CSSProperties;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const VIEW_BOX_SIZE = 100;
|
|
2
|
+
export const getCircleStyle = (perimeter, perimeterWithoutGap, offset, percent, rotateDeg, gapDegree, gapPosition, strokeColor, strokeLinecap, strokeWidth, stepSpace = 0) => {
|
|
3
|
+
const offsetDeg = offset / 100 * 360 * ((360 - gapDegree) / 360);
|
|
4
|
+
const positionDeg = gapDegree === 0 ? 0 : {
|
|
5
|
+
bottom: 0,
|
|
6
|
+
top: 180,
|
|
7
|
+
left: 90,
|
|
8
|
+
right: -90
|
|
9
|
+
}[gapPosition];
|
|
10
|
+
let strokeDashoffset = (100 - percent) / 100 * perimeterWithoutGap;
|
|
11
|
+
// Fix percent accuracy when strokeLinecap is round
|
|
12
|
+
// https://github.com/ant-design/ant-design/issues/35009
|
|
13
|
+
if (strokeLinecap === 'round' && percent !== 100) {
|
|
14
|
+
strokeDashoffset += strokeWidth / 2;
|
|
15
|
+
// when percent is small enough (<= 1%), keep smallest value to avoid it's disappearance
|
|
16
|
+
if (strokeDashoffset >= perimeterWithoutGap) {
|
|
17
|
+
strokeDashoffset = perimeterWithoutGap - 0.01;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const halfSize = VIEW_BOX_SIZE / 2;
|
|
21
|
+
return {
|
|
22
|
+
stroke: typeof strokeColor === 'string' ? strokeColor : undefined,
|
|
23
|
+
strokeDasharray: `${perimeterWithoutGap}px ${perimeter}`,
|
|
24
|
+
strokeDashoffset: strokeDashoffset + stepSpace,
|
|
25
|
+
transform: `rotate(${rotateDeg + offsetDeg + positionDeg}deg)`,
|
|
26
|
+
transformOrigin: `${halfSize}px ${halfSize}px`,
|
|
27
|
+
transition: 'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s',
|
|
28
|
+
fillOpacity: 0
|
|
29
|
+
};
|
|
30
|
+
};
|
package/es/Line.d.ts
ADDED
package/es/Line.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import { useTransitionDuration, defaultProps } from "./common";
|
|
5
|
+
import getIndeterminateLine from "./utils/getIndeterminateLine";
|
|
6
|
+
import useId from "@rc-component/util/es/hooks/useId";
|
|
7
|
+
const Line = props => {
|
|
8
|
+
const {
|
|
9
|
+
id,
|
|
10
|
+
className,
|
|
11
|
+
percent,
|
|
12
|
+
prefixCls,
|
|
13
|
+
strokeColor,
|
|
14
|
+
strokeLinecap,
|
|
15
|
+
strokeWidth,
|
|
16
|
+
style,
|
|
17
|
+
trailColor,
|
|
18
|
+
trailWidth,
|
|
19
|
+
transition,
|
|
20
|
+
loading,
|
|
21
|
+
...restProps
|
|
22
|
+
} = {
|
|
23
|
+
...defaultProps,
|
|
24
|
+
...props
|
|
25
|
+
};
|
|
26
|
+
const mergedId = useId(id);
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line no-param-reassign
|
|
29
|
+
delete restProps.gapPosition;
|
|
30
|
+
const percentList = Array.isArray(percent) ? percent : [percent];
|
|
31
|
+
const strokeColorList = Array.isArray(strokeColor) ? strokeColor : [strokeColor];
|
|
32
|
+
const paths = useTransitionDuration();
|
|
33
|
+
const center = strokeWidth / 2;
|
|
34
|
+
const right = 100 - strokeWidth / 2;
|
|
35
|
+
const pathString = `M ${strokeLinecap === 'round' ? center : 0},${center}
|
|
36
|
+
L ${strokeLinecap === 'round' ? right : 100},${center}`;
|
|
37
|
+
const viewBoxString = `0 0 100 ${strokeWidth}`;
|
|
38
|
+
let stackPtg = 0;
|
|
39
|
+
const {
|
|
40
|
+
indeterminateStyleProps,
|
|
41
|
+
indeterminateStyleAnimation
|
|
42
|
+
} = getIndeterminateLine({
|
|
43
|
+
id: mergedId,
|
|
44
|
+
loading,
|
|
45
|
+
percent: percentList[0],
|
|
46
|
+
strokeLinecap,
|
|
47
|
+
strokeWidth
|
|
48
|
+
});
|
|
49
|
+
return /*#__PURE__*/React.createElement("svg", _extends({
|
|
50
|
+
className: classNames(`${prefixCls}-line`, className),
|
|
51
|
+
viewBox: viewBoxString,
|
|
52
|
+
preserveAspectRatio: "none",
|
|
53
|
+
style: style
|
|
54
|
+
}, restProps), /*#__PURE__*/React.createElement("path", {
|
|
55
|
+
className: `${prefixCls}-line-trail`,
|
|
56
|
+
d: pathString,
|
|
57
|
+
strokeLinecap: strokeLinecap,
|
|
58
|
+
stroke: trailColor,
|
|
59
|
+
strokeWidth: trailWidth || strokeWidth,
|
|
60
|
+
fillOpacity: "0"
|
|
61
|
+
}), percentList.map((ptg, index) => {
|
|
62
|
+
let dashPercent = 1;
|
|
63
|
+
switch (strokeLinecap) {
|
|
64
|
+
case 'round':
|
|
65
|
+
dashPercent = 1 - strokeWidth / 100;
|
|
66
|
+
break;
|
|
67
|
+
case 'square':
|
|
68
|
+
dashPercent = 1 - strokeWidth / 2 / 100;
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
dashPercent = 1;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
const pathStyle = {
|
|
75
|
+
strokeDasharray: `${ptg * dashPercent}px, 100px`,
|
|
76
|
+
strokeDashoffset: `-${stackPtg}px`,
|
|
77
|
+
transition: transition || 'stroke-dashoffset 0.3s ease 0s, stroke-dasharray .3s ease 0s, stroke 0.3s linear',
|
|
78
|
+
...indeterminateStyleProps
|
|
79
|
+
};
|
|
80
|
+
const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1];
|
|
81
|
+
stackPtg += ptg;
|
|
82
|
+
return /*#__PURE__*/React.createElement("path", {
|
|
83
|
+
key: index,
|
|
84
|
+
className: `${prefixCls}-line-path`,
|
|
85
|
+
d: pathString,
|
|
86
|
+
strokeLinecap: strokeLinecap,
|
|
87
|
+
stroke: color,
|
|
88
|
+
strokeWidth: strokeWidth,
|
|
89
|
+
fillOpacity: "0",
|
|
90
|
+
ref: elem => {
|
|
91
|
+
// https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
|
|
92
|
+
// React will call the ref callback with the DOM element when the component mounts,
|
|
93
|
+
// and call it with `null` when it unmounts.
|
|
94
|
+
// Refs are guaranteed to be up-to-date before componentDidMount or componentDidUpdate fires.
|
|
95
|
+
|
|
96
|
+
paths[index] = elem;
|
|
97
|
+
},
|
|
98
|
+
style: pathStyle
|
|
99
|
+
});
|
|
100
|
+
}), indeterminateStyleAnimation);
|
|
101
|
+
};
|
|
102
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
103
|
+
Line.displayName = 'Line';
|
|
104
|
+
}
|
|
105
|
+
export default Line;
|
package/es/common.d.ts
ADDED
package/es/common.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRef, useEffect } from 'react';
|
|
2
|
+
export const defaultProps = {
|
|
3
|
+
percent: 0,
|
|
4
|
+
prefixCls: 'rc-progress',
|
|
5
|
+
strokeColor: '#2db7f5',
|
|
6
|
+
strokeLinecap: 'round',
|
|
7
|
+
strokeWidth: 1,
|
|
8
|
+
trailColor: '#D9D9D9',
|
|
9
|
+
trailWidth: 1,
|
|
10
|
+
gapPosition: 'bottom',
|
|
11
|
+
loading: false
|
|
12
|
+
};
|
|
13
|
+
export const useTransitionDuration = () => {
|
|
14
|
+
const pathsRef = useRef([]);
|
|
15
|
+
const prevTimeStamp = useRef(null);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
let updated = false;
|
|
19
|
+
pathsRef.current.forEach(path => {
|
|
20
|
+
if (!path) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
updated = true;
|
|
24
|
+
const pathStyle = path.style;
|
|
25
|
+
pathStyle.transitionDuration = '.3s, .3s, .3s, .06s';
|
|
26
|
+
if (prevTimeStamp.current && now - prevTimeStamp.current < 100) {
|
|
27
|
+
pathStyle.transitionDuration = '0s, 0s';
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (updated) {
|
|
31
|
+
prevTimeStamp.current = Date.now();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return pathsRef.current;
|
|
35
|
+
};
|
package/es/index.d.ts
ADDED
package/es/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export type SemanticName = 'root' | 'rail' | 'track';
|
|
3
|
+
export interface ProgressProps {
|
|
4
|
+
id?: string;
|
|
5
|
+
strokeWidth?: number;
|
|
6
|
+
trailWidth?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
classNames?: Partial<Record<SemanticName, string>>;
|
|
9
|
+
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
|
|
10
|
+
percent?: number | number[];
|
|
11
|
+
strokeColor?: StrokeColorType;
|
|
12
|
+
trailColor?: string;
|
|
13
|
+
strokeLinecap?: StrokeLinecapType;
|
|
14
|
+
prefixCls?: string;
|
|
15
|
+
style?: React.CSSProperties;
|
|
16
|
+
gapDegree?: number;
|
|
17
|
+
gapPosition?: GapPositionType;
|
|
18
|
+
transition?: string;
|
|
19
|
+
onClick?: React.MouseEventHandler;
|
|
20
|
+
steps?: number | {
|
|
21
|
+
count: number;
|
|
22
|
+
gap: number;
|
|
23
|
+
};
|
|
24
|
+
loading?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type StrokeColorObject = Record<string, string | boolean>;
|
|
27
|
+
export type BaseStrokeColorType = string | StrokeColorObject;
|
|
28
|
+
export type StrokeColorType = BaseStrokeColorType | BaseStrokeColorType[];
|
|
29
|
+
export type GapPositionType = 'top' | 'right' | 'bottom' | 'left';
|
|
30
|
+
export type StrokeLinecapType = 'round' | 'butt' | 'square';
|
package/es/interface.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|