Skip to content

Commit 2ba963b

Browse files
authored
refactor(progress): use composition API (#4355)
* refactor(progress): use composition API * refactor(vc-progress): update
1 parent 8ce46ab commit 2ba963b

24 files changed

+1221
-662
lines changed

components/progress/Circle.tsx

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import type { CSSProperties, ExtractPropTypes } from 'vue';
2+
import { computed, defineComponent } from 'vue';
3+
import { Circle as VCCircle } from '../vc-progress';
4+
import { getSuccessPercent, validProgress } from './utils';
5+
import { progressProps } from './props';
6+
import PropTypes from '../_util/vue-types';
7+
8+
const circleProps = {
9+
...progressProps,
10+
prefixCls: PropTypes.string,
11+
// progressStatus: PropTypes.string,
12+
};
13+
export type CircleProps = Partial<ExtractPropTypes<typeof circleProps>>;
14+
15+
const statusColorMap = {
16+
normal: '#108ee9',
17+
exception: '#ff5500',
18+
success: '#87d068',
19+
};
20+
21+
function getPercentage(
22+
percent: CircleProps['percent'],
23+
success: CircleProps['success'],
24+
successPercent: CircleProps['successPercent'],
25+
) {
26+
const ptg = validProgress(percent);
27+
const realSuccessPercent = getSuccessPercent(success, successPercent);
28+
if (!realSuccessPercent) {
29+
return ptg;
30+
}
31+
return [
32+
validProgress(realSuccessPercent),
33+
validProgress(ptg - validProgress(realSuccessPercent)),
34+
];
35+
}
36+
37+
function getStrokeColor(
38+
success: CircleProps['success'],
39+
strokeColor: CircleProps['strokeColor'],
40+
successPercent: CircleProps['successPercent'],
41+
) {
42+
const color = strokeColor || null;
43+
const realSuccessPercent = getSuccessPercent(success, successPercent);
44+
if (!realSuccessPercent) {
45+
return color;
46+
}
47+
return [statusColorMap.success, color];
48+
}
49+
50+
export default defineComponent({
51+
props: progressProps,
52+
inheritAttrs: false,
53+
setup(props, { slots }) {
54+
const gapDeg = computed(() => {
55+
// Support gapDeg = 0 when type = 'dashboard'
56+
if (props.gapDegree || props.gapDegree === 0) {
57+
return props.gapDegree;
58+
}
59+
if (props.type === 'dashboard') {
60+
return 75;
61+
}
62+
return undefined;
63+
});
64+
65+
const circleStyle = computed<CSSProperties>(() => {
66+
const circleSize = props.width || 120;
67+
return {
68+
width: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
69+
height: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
70+
fontSize: `${circleSize * 0.15 + 6}px`,
71+
};
72+
});
73+
74+
const circleWidth = computed(() => props.strokeWidth || 6);
75+
const gapPos = computed(
76+
() => props.gapPosition || (props.type === 'dashboard' && 'bottom') || 'top',
77+
);
78+
79+
// using className to style stroke color
80+
const strokeColor = computed(() =>
81+
getStrokeColor(props.success, props.strokeColor, props.successPercent),
82+
);
83+
const percent = computed(() =>
84+
getPercentage(props.percent, props.success, props.successPercent),
85+
);
86+
const isGradient = computed(
87+
() => Object.prototype.toString.call(strokeColor.value) === '[object Object]',
88+
);
89+
90+
const wrapperClassName = computed(() => ({
91+
[`${props.prefixCls}-inner`]: true,
92+
[`${props.prefixCls}-circle-gradient`]: isGradient.value,
93+
}));
94+
95+
return () => (
96+
<div class={wrapperClassName.value} style={circleStyle.value}>
97+
<VCCircle
98+
percent={percent.value}
99+
strokeWidth={circleWidth.value}
100+
trailWidth={circleWidth.value}
101+
strokeColor={strokeColor.value}
102+
strokeLinecap={props.strokeLinecap}
103+
trailColor={props.trailColor}
104+
prefixCls={props.prefixCls}
105+
gapDegree={gapDeg.value}
106+
gapPosition={gapPos.value}
107+
/>
108+
{slots.default?.()}
109+
</div>
110+
);
111+
},
112+
});

components/progress/Line.tsx

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
2+
import { computed, defineComponent } from 'vue';
3+
import type { Direction } from '../config-provider';
4+
import PropTypes from '../_util/vue-types';
5+
import type { StringGradients, ProgressGradient } from './props';
6+
import { progressProps } from './props';
7+
import { getSuccessPercent, validProgress } from './utils';
8+
9+
const lineProps = {
10+
...progressProps,
11+
prefixCls: PropTypes.string,
12+
direction: {
13+
type: String as PropType<Direction>,
14+
},
15+
};
16+
17+
export type LineProps = Partial<ExtractPropTypes<typeof lineProps>>;
18+
19+
/**
20+
* {
21+
* '0%': '#afc163',
22+
* '75%': '#009900',
23+
* '50%': 'green', ====> '#afc163 0%, #66FF00 25%, #00CC00 50%, #009900 75%, #ffffff 100%'
24+
* '25%': '#66FF00',
25+
* '100%': '#ffffff'
26+
* }
27+
*/
28+
export const sortGradient = (gradients: StringGradients) => {
29+
let tempArr = [];
30+
Object.keys(gradients).forEach(key => {
31+
const formattedKey = parseFloat(key.replace(/%/g, ''));
32+
if (!isNaN(formattedKey)) {
33+
tempArr.push({
34+
key: formattedKey,
35+
value: gradients[key],
36+
});
37+
}
38+
});
39+
tempArr = tempArr.sort((a, b) => a.key - b.key);
40+
return tempArr.map(({ key, value }) => `${value} ${key}%`).join(', ');
41+
};
42+
43+
/**
44+
* Then this man came to realize the truth: Besides six pence, there is the moon. Besides bread and
45+
* butter, there is the bug. And... Besides women, there is the code.
46+
*
47+
* @example
48+
* {
49+
* "0%": "#afc163",
50+
* "25%": "#66FF00",
51+
* "50%": "#00CC00", // ====> linear-gradient(to right, #afc163 0%, #66FF00 25%,
52+
* "75%": "#009900", // #00CC00 50%, #009900 75%, #ffffff 100%)
53+
* "100%": "#ffffff"
54+
* }
55+
*/
56+
export const handleGradient = (strokeColor: ProgressGradient, directionConfig: Direction) => {
57+
const {
58+
from = '#1890ff',
59+
to = '#1890ff',
60+
direction = directionConfig === 'rtl' ? 'to left' : 'to right',
61+
...rest
62+
} = strokeColor;
63+
if (Object.keys(rest).length !== 0) {
64+
const sortedGradients = sortGradient(rest as StringGradients);
65+
return { backgroundImage: `linear-gradient(${direction}, ${sortedGradients})` };
66+
}
67+
return { backgroundImage: `linear-gradient(${direction}, ${from}, ${to})` };
68+
};
69+
70+
export default defineComponent({
71+
props: lineProps,
72+
setup(props, { slots }) {
73+
const backgroundProps = computed(() => {
74+
const { strokeColor, direction } = props;
75+
return strokeColor && typeof strokeColor !== 'string'
76+
? handleGradient(strokeColor, direction)
77+
: {
78+
background: strokeColor,
79+
};
80+
});
81+
82+
const trailStyle = computed(() =>
83+
props.trailColor
84+
? {
85+
backgroundColor: props.trailColor,
86+
}
87+
: undefined,
88+
);
89+
90+
const percentStyle = computed<CSSProperties>(() => {
91+
const { percent, strokeWidth, strokeLinecap, size } = props;
92+
return {
93+
width: `${validProgress(percent)}%`,
94+
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
95+
borderRadius: strokeLinecap === 'square' ? 0 : '',
96+
...(backgroundProps.value as any),
97+
};
98+
});
99+
100+
const successPercent = computed(() => {
101+
return getSuccessPercent(props.success, props.successPercent);
102+
});
103+
const successPercentStyle = computed<CSSProperties>(() => {
104+
const { strokeWidth, size, strokeLinecap, success } = props;
105+
return {
106+
width: `${validProgress(successPercent.value)}%`,
107+
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
108+
borderRadius: strokeLinecap === 'square' ? 0 : '',
109+
backgroundColor: success?.strokeColor,
110+
};
111+
});
112+
113+
const successSegment = computed(() =>
114+
successPercent.value !== undefined ? (
115+
<div class={`${props.prefixCls}-success-bg`} style={successPercentStyle.value} />
116+
) : null,
117+
);
118+
119+
return () => (
120+
<>
121+
<div class={`${props.prefixCls}-outer`}>
122+
<div class={`${props.prefixCls}-inner`} style={trailStyle.value}>
123+
<div class={`${props.prefixCls}-bg`} style={percentStyle.value} />
124+
{successSegment.value}
125+
</div>
126+
</div>
127+
{slots.default?.()}
128+
</>
129+
);
130+
},
131+
});

components/progress/Steps.tsx

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { computed, ExtractPropTypes, PropType, VNodeChild } from 'vue';
2+
import { defineComponent } from 'vue';
3+
import PropTypes from '../_util/vue-types';
4+
import type { ProgressSize } from './props';
5+
import { progressProps } from './props';
6+
7+
const stepsProps = {
8+
...progressProps,
9+
steps: PropTypes.number,
10+
size: {
11+
type: String as PropType<ProgressSize>,
12+
},
13+
strokeColor: PropTypes.string,
14+
trailColor: PropTypes.string,
15+
};
16+
17+
export type StepsProps = Partial<ExtractPropTypes<typeof stepsProps>>;
18+
19+
export default defineComponent({
20+
props: stepsProps,
21+
setup(props, { slots }) {
22+
const current = computed(() => Math.round(props.steps * ((props.percent || 0) / 100)));
23+
const stepWidth = computed(() => (props.size === 'small' ? 2 : 14));
24+
25+
const styledSteps = computed(() => {
26+
const { steps, strokeWidth = 8, strokeColor, trailColor, prefixCls } = props;
27+
28+
const temp: VNodeChild[] = [];
29+
for (let i = 0; i < steps; i += 1) {
30+
const cls = {
31+
[`${prefixCls}-steps-item`]: true,
32+
[`${prefixCls}-steps-item-active`]: i <= current.value - 1,
33+
};
34+
temp.push(
35+
<div
36+
key={i}
37+
class={cls}
38+
style={{
39+
backgroundColor: i <= current.value - 1 ? strokeColor : trailColor,
40+
width: `${stepWidth.value}px`,
41+
height: `${strokeWidth}px`,
42+
}}
43+
/>,
44+
);
45+
}
46+
return temp;
47+
});
48+
49+
return () => (
50+
<div class={`${props.prefixCls}-steps-outer`}>
51+
{styledSteps.value}
52+
{slots.default?.()}
53+
</div>
54+
);
55+
},
56+
});

0 commit comments

Comments
 (0)