refactor(progress): use composition API (#4355)
* refactor(progress): use composition API * refactor(vc-progress): updaterefactor-progress^2
parent
8ce46ab1a1
commit
2ba963babf
|
@ -0,0 +1,112 @@
|
||||||
|
import type { CSSProperties, ExtractPropTypes } from 'vue';
|
||||||
|
import { computed, defineComponent } from 'vue';
|
||||||
|
import { Circle as VCCircle } from '../vc-progress';
|
||||||
|
import { getSuccessPercent, validProgress } from './utils';
|
||||||
|
import { progressProps } from './props';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
|
||||||
|
const circleProps = {
|
||||||
|
...progressProps,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
// progressStatus: PropTypes.string,
|
||||||
|
};
|
||||||
|
export type CircleProps = Partial<ExtractPropTypes<typeof circleProps>>;
|
||||||
|
|
||||||
|
const statusColorMap = {
|
||||||
|
normal: '#108ee9',
|
||||||
|
exception: '#ff5500',
|
||||||
|
success: '#87d068',
|
||||||
|
};
|
||||||
|
|
||||||
|
function getPercentage(
|
||||||
|
percent: CircleProps['percent'],
|
||||||
|
success: CircleProps['success'],
|
||||||
|
successPercent: CircleProps['successPercent'],
|
||||||
|
) {
|
||||||
|
const ptg = validProgress(percent);
|
||||||
|
const realSuccessPercent = getSuccessPercent(success, successPercent);
|
||||||
|
if (!realSuccessPercent) {
|
||||||
|
return ptg;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
validProgress(realSuccessPercent),
|
||||||
|
validProgress(ptg - validProgress(realSuccessPercent)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStrokeColor(
|
||||||
|
success: CircleProps['success'],
|
||||||
|
strokeColor: CircleProps['strokeColor'],
|
||||||
|
successPercent: CircleProps['successPercent'],
|
||||||
|
) {
|
||||||
|
const color = strokeColor || null;
|
||||||
|
const realSuccessPercent = getSuccessPercent(success, successPercent);
|
||||||
|
if (!realSuccessPercent) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
return [statusColorMap.success, color];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: progressProps,
|
||||||
|
inheritAttrs: false,
|
||||||
|
setup(props, { slots }) {
|
||||||
|
const gapDeg = computed(() => {
|
||||||
|
// Support gapDeg = 0 when type = 'dashboard'
|
||||||
|
if (props.gapDegree || props.gapDegree === 0) {
|
||||||
|
return props.gapDegree;
|
||||||
|
}
|
||||||
|
if (props.type === 'dashboard') {
|
||||||
|
return 75;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const circleStyle = computed<CSSProperties>(() => {
|
||||||
|
const circleSize = props.width || 120;
|
||||||
|
return {
|
||||||
|
width: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
|
||||||
|
height: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
|
||||||
|
fontSize: `${circleSize * 0.15 + 6}px`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const circleWidth = computed(() => props.strokeWidth || 6);
|
||||||
|
const gapPos = computed(
|
||||||
|
() => props.gapPosition || (props.type === 'dashboard' && 'bottom') || 'top',
|
||||||
|
);
|
||||||
|
|
||||||
|
// using className to style stroke color
|
||||||
|
const strokeColor = computed(() =>
|
||||||
|
getStrokeColor(props.success, props.strokeColor, props.successPercent),
|
||||||
|
);
|
||||||
|
const percent = computed(() =>
|
||||||
|
getPercentage(props.percent, props.success, props.successPercent),
|
||||||
|
);
|
||||||
|
const isGradient = computed(
|
||||||
|
() => Object.prototype.toString.call(strokeColor.value) === '[object Object]',
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrapperClassName = computed(() => ({
|
||||||
|
[`${props.prefixCls}-inner`]: true,
|
||||||
|
[`${props.prefixCls}-circle-gradient`]: isGradient.value,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<div class={wrapperClassName.value} style={circleStyle.value}>
|
||||||
|
<VCCircle
|
||||||
|
percent={percent.value}
|
||||||
|
strokeWidth={circleWidth.value}
|
||||||
|
trailWidth={circleWidth.value}
|
||||||
|
strokeColor={strokeColor.value}
|
||||||
|
strokeLinecap={props.strokeLinecap}
|
||||||
|
trailColor={props.trailColor}
|
||||||
|
prefixCls={props.prefixCls}
|
||||||
|
gapDegree={gapDeg.value}
|
||||||
|
gapPosition={gapPos.value}
|
||||||
|
/>
|
||||||
|
{slots.default?.()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,131 @@
|
||||||
|
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
||||||
|
import { computed, defineComponent } from 'vue';
|
||||||
|
import type { Direction } from '../config-provider';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
import type { StringGradients, ProgressGradient } from './props';
|
||||||
|
import { progressProps } from './props';
|
||||||
|
import { getSuccessPercent, validProgress } from './utils';
|
||||||
|
|
||||||
|
const lineProps = {
|
||||||
|
...progressProps,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
direction: {
|
||||||
|
type: String as PropType<Direction>,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LineProps = Partial<ExtractPropTypes<typeof lineProps>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {
|
||||||
|
* '0%': '#afc163',
|
||||||
|
* '75%': '#009900',
|
||||||
|
* '50%': 'green', ====> '#afc163 0%, #66FF00 25%, #00CC00 50%, #009900 75%, #ffffff 100%'
|
||||||
|
* '25%': '#66FF00',
|
||||||
|
* '100%': '#ffffff'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const sortGradient = (gradients: StringGradients) => {
|
||||||
|
let tempArr = [];
|
||||||
|
Object.keys(gradients).forEach(key => {
|
||||||
|
const formattedKey = parseFloat(key.replace(/%/g, ''));
|
||||||
|
if (!isNaN(formattedKey)) {
|
||||||
|
tempArr.push({
|
||||||
|
key: formattedKey,
|
||||||
|
value: gradients[key],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tempArr = tempArr.sort((a, b) => a.key - b.key);
|
||||||
|
return tempArr.map(({ key, value }) => `${value} ${key}%`).join(', ');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Then this man came to realize the truth: Besides six pence, there is the moon. Besides bread and
|
||||||
|
* butter, there is the bug. And... Besides women, there is the code.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* {
|
||||||
|
* "0%": "#afc163",
|
||||||
|
* "25%": "#66FF00",
|
||||||
|
* "50%": "#00CC00", // ====> linear-gradient(to right, #afc163 0%, #66FF00 25%,
|
||||||
|
* "75%": "#009900", // #00CC00 50%, #009900 75%, #ffffff 100%)
|
||||||
|
* "100%": "#ffffff"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const handleGradient = (strokeColor: ProgressGradient, directionConfig: Direction) => {
|
||||||
|
const {
|
||||||
|
from = '#1890ff',
|
||||||
|
to = '#1890ff',
|
||||||
|
direction = directionConfig === 'rtl' ? 'to left' : 'to right',
|
||||||
|
...rest
|
||||||
|
} = strokeColor;
|
||||||
|
if (Object.keys(rest).length !== 0) {
|
||||||
|
const sortedGradients = sortGradient(rest as StringGradients);
|
||||||
|
return { backgroundImage: `linear-gradient(${direction}, ${sortedGradients})` };
|
||||||
|
}
|
||||||
|
return { backgroundImage: `linear-gradient(${direction}, ${from}, ${to})` };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: lineProps,
|
||||||
|
setup(props, { slots }) {
|
||||||
|
const backgroundProps = computed(() => {
|
||||||
|
const { strokeColor, direction } = props;
|
||||||
|
return strokeColor && typeof strokeColor !== 'string'
|
||||||
|
? handleGradient(strokeColor, direction)
|
||||||
|
: {
|
||||||
|
background: strokeColor,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const trailStyle = computed(() =>
|
||||||
|
props.trailColor
|
||||||
|
? {
|
||||||
|
backgroundColor: props.trailColor,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const percentStyle = computed<CSSProperties>(() => {
|
||||||
|
const { percent, strokeWidth, strokeLinecap, size } = props;
|
||||||
|
return {
|
||||||
|
width: `${validProgress(percent)}%`,
|
||||||
|
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
|
||||||
|
borderRadius: strokeLinecap === 'square' ? 0 : '',
|
||||||
|
...(backgroundProps.value as any),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const successPercent = computed(() => {
|
||||||
|
return getSuccessPercent(props.success, props.successPercent);
|
||||||
|
});
|
||||||
|
const successPercentStyle = computed<CSSProperties>(() => {
|
||||||
|
const { strokeWidth, size, strokeLinecap, success } = props;
|
||||||
|
return {
|
||||||
|
width: `${validProgress(successPercent.value)}%`,
|
||||||
|
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
|
||||||
|
borderRadius: strokeLinecap === 'square' ? 0 : '',
|
||||||
|
backgroundColor: success?.strokeColor,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const successSegment = computed(() =>
|
||||||
|
successPercent.value !== undefined ? (
|
||||||
|
<div class={`${props.prefixCls}-success-bg`} style={successPercentStyle.value} />
|
||||||
|
) : null,
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<>
|
||||||
|
<div class={`${props.prefixCls}-outer`}>
|
||||||
|
<div class={`${props.prefixCls}-inner`} style={trailStyle.value}>
|
||||||
|
<div class={`${props.prefixCls}-bg`} style={percentStyle.value} />
|
||||||
|
{successSegment.value}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{slots.default?.()}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { computed, ExtractPropTypes, PropType, VNodeChild } from 'vue';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
import type { ProgressSize } from './props';
|
||||||
|
import { progressProps } from './props';
|
||||||
|
|
||||||
|
const stepsProps = {
|
||||||
|
...progressProps,
|
||||||
|
steps: PropTypes.number,
|
||||||
|
size: {
|
||||||
|
type: String as PropType<ProgressSize>,
|
||||||
|
},
|
||||||
|
strokeColor: PropTypes.string,
|
||||||
|
trailColor: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StepsProps = Partial<ExtractPropTypes<typeof stepsProps>>;
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: stepsProps,
|
||||||
|
setup(props, { slots }) {
|
||||||
|
const current = computed(() => Math.round(props.steps * ((props.percent || 0) / 100)));
|
||||||
|
const stepWidth = computed(() => (props.size === 'small' ? 2 : 14));
|
||||||
|
|
||||||
|
const styledSteps = computed(() => {
|
||||||
|
const { steps, strokeWidth = 8, strokeColor, trailColor, prefixCls } = props;
|
||||||
|
|
||||||
|
const temp: VNodeChild[] = [];
|
||||||
|
for (let i = 0; i < steps; i += 1) {
|
||||||
|
const cls = {
|
||||||
|
[`${prefixCls}-steps-item`]: true,
|
||||||
|
[`${prefixCls}-steps-item-active`]: i <= current.value - 1,
|
||||||
|
};
|
||||||
|
temp.push(
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
class={cls}
|
||||||
|
style={{
|
||||||
|
backgroundColor: i <= current.value - 1 ? strokeColor : trailColor,
|
||||||
|
width: `${stepWidth.value}px`,
|
||||||
|
height: `${strokeWidth}px`,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<div class={`${props.prefixCls}-steps-outer`}>
|
||||||
|
{styledSteps.value}
|
||||||
|
{slots.default?.()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,7 +1,115 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Progress render dashboard 295 gapDegree 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-circle ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-inner" style="width: 120px; height: 120px; font-size: 24px;"><svg class="ant-progress-circle" viewBox="0 0 100 100">
|
||||||
|
<!---->
|
||||||
|
<path d="M 50,50 m 0,47
|
||||||
|
a 47,47 0 1 1 0,-94
|
||||||
|
a 47,47 0 1 1 0,94" stroke-linecap="round" stroke-width="6" fill-opacity="0" class="ant-progress-circle-trail" style="stroke-dasharray: 0.3097094374405742px 295.3097094374406px; stroke-dashoffset: -147.5px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"></path>
|
||||||
|
<path d="M 50,50 m 0,47
|
||||||
|
a 47,47 0 1 1 0,-94
|
||||||
|
a 47,47 0 1 1 0,94" stroke="" stroke-linecap="round" stroke-width="6" opacity="0" fill-opacity="0" class="ant-progress-circle-path" style="stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -147.5px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"></path>
|
||||||
|
</svg><span class="ant-progress-text" title="0%">0%</span></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render dashboard 296 gapDegree 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-circle ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-inner" style="width: 120px; height: 120px; font-size: 24px;"><svg class="ant-progress-circle" viewBox="0 0 100 100">
|
||||||
|
<!---->
|
||||||
|
<path d="M 50,50 m 0,47
|
||||||
|
a 47,47 0 1 1 0,-94
|
||||||
|
a 47,47 0 1 1 0,94" stroke-linecap="round" stroke-width="6" fill-opacity="0" class="ant-progress-circle-trail" style="stroke-dasharray: -0.6902905625594258px 295.3097094374406px; stroke-dashoffset: -148px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"></path>
|
||||||
|
<path d="M 50,50 m 0,47
|
||||||
|
a 47,47 0 1 1 0,-94
|
||||||
|
a 47,47 0 1 1 0,94" stroke="" stroke-linecap="round" stroke-width="6" opacity="0" fill-opacity="0" class="ant-progress-circle-path" style="stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -148px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"></path>
|
||||||
|
</svg><span class="ant-progress-text" title="0%">0%</span></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render dashboard zero gapDegree 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-circle ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-inner" style="width: 120px; height: 120px; font-size: 24px;"><svg class="ant-progress-circle" viewBox="0 0 100 100">
|
||||||
|
<!---->
|
||||||
|
<path d="M 50,50 m 0,47
|
||||||
|
a 47,47 0 1 1 0,-94
|
||||||
|
a 47,47 0 1 1 0,94" stroke-linecap="round" stroke-width="6" fill-opacity="0" class="ant-progress-circle-trail" style="stroke-dasharray: 295.3097094374406px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"></path>
|
||||||
|
<path d="M 50,50 m 0,47
|
||||||
|
a 47,47 0 1 1 0,-94
|
||||||
|
a 47,47 0 1 1 0,94" stroke="" stroke-linecap="round" stroke-width="6" opacity="0" fill-opacity="0" class="ant-progress-circle-path" style="stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;"></path>
|
||||||
|
</svg><span class="ant-progress-text" title="0%">0%</span></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`Progress render format 1`] = `
|
exports[`Progress render format 1`] = `
|
||||||
<div class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default">
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 50%; height: 8px;"></div>
|
||||||
|
<div class="ant-progress-success-bg" style="width: 10%; height: 8px;"></div>
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="50 10">50 10</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render negative progress 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 0%; height: 8px;"></div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="0%">0%</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render negative successPercent 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 50%; height: 8px;"></div>
|
||||||
|
<div class="ant-progress-success-bg" style="width: 0%; height: 8px;"></div>
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="50%">50%</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render normal progress 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 0%; height: 8px;"></div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="0%">0%</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render out-of-range progress 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-success">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 100%; height: 8px;"></div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text"><span role="img" aria-label="check-circle" class="anticon anticon-check-circle"><svg focusable="false" class="" data-icon="check-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path></svg></span></span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render out-of-range progress with info 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-success">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 100%; height: 8px;"></div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text"><span role="img" aria-label="check-circle" class="anticon anticon-check-circle"><svg focusable="false" class="" data-icon="check-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path></svg></span></span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render strokeColor 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-circle ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
<div class="ant-progress-inner" style="width: 120px; height: 120px; font-size: 24px;"><svg class="ant-progress-circle" viewBox="0 0 100 100">
|
<div class="ant-progress-inner" style="width: 120px; height: 120px; font-size: 24px;"><svg class="ant-progress-circle" viewBox="0 0 100 100">
|
||||||
<!---->
|
<!---->
|
||||||
<path d="M 50,50 m 0,-47
|
<path d="M 50,50 m 0,-47
|
||||||
|
@ -14,80 +122,62 @@ exports[`Progress render format 1`] = `
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Progress render negetive progress 1`] = `
|
exports[`Progress render strokeColor 2`] = `
|
||||||
<div class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default">
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
<div>
|
<div class="ant-progress-outer">
|
||||||
<div class="ant-progress-outer">
|
<div class="ant-progress-inner">
|
||||||
<div class="ant-progress-inner">
|
<div class="ant-progress-bg" style="width: 50%; height: 8px;"></div>
|
||||||
<div class="ant-progress-bg" style="width: 0%; height: 8px; border-radius: 100px;"></div>
|
<!---->
|
||||||
<!---->
|
</div>
|
||||||
</div>
|
</div><span class="ant-progress-text" title="50%">50%</span>
|
||||||
</div><span class="ant-progress-text" title="0%">0%</span>
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render strokeColor 3`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 50%; height: 8px;"></div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="50%">50%</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render successColor progress 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner">
|
||||||
|
<div class="ant-progress-bg" style="width: 60%; height: 8px;"></div>
|
||||||
|
<div class="ant-progress-success-bg" style="width: 30%; height: 8px; background-color: rgb(255, 255, 255);"></div>
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="60%">60%</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress render trailColor progress 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-outer">
|
||||||
|
<div class="ant-progress-inner" style="background-color: rgb(255, 255, 255);">
|
||||||
|
<div class="ant-progress-bg" style="width: 0%; height: 8px;"></div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div><span class="ant-progress-text" title="0%">0%</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Progress should support steps 1`] = `
|
||||||
|
<div class="ant-progress ant-progress-line ant-progress-show-info ant-progress-default ant-progress-status-normal">
|
||||||
|
<div class="ant-progress-steps-outer">
|
||||||
|
<div class="ant-progress-steps-item" style="width: 14px; height: 8px;"></div>
|
||||||
|
<div class="ant-progress-steps-item" style="width: 14px; height: 8px;"></div>
|
||||||
|
<div class="ant-progress-steps-item" style="width: 14px; height: 8px;"></div><span class="ant-progress-text" title="0%">0%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Progress render negetive successPercent 1`] = `
|
exports[`Progress steps should have default percent 0 1`] = `
|
||||||
<div class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default">
|
<div class="undefined-steps-outer">
|
||||||
<div>
|
<!---->
|
||||||
<div class="ant-progress-outer">
|
|
||||||
<div class="ant-progress-inner">
|
|
||||||
<div class="ant-progress-bg" style="width: 50%; height: 8px; border-radius: 100px;"></div>
|
|
||||||
<div class="ant-progress-success-bg" style="width: 0%; height: 8px;"></div>
|
|
||||||
</div>
|
|
||||||
</div><span class="ant-progress-text" title="50%">50%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Progress render negetive successPercent 2`] = `
|
|
||||||
<div class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default">
|
|
||||||
<div>
|
|
||||||
<div class="ant-progress-outer">
|
|
||||||
<div class="ant-progress-inner">
|
|
||||||
<div class="ant-progress-bg" style="width: 50%; height: 8px; border-radius: 100px;"></div>
|
|
||||||
<div class="ant-progress-success-bg" style="width: 10%; height: 8px;"></div>
|
|
||||||
</div>
|
|
||||||
</div><span class="ant-progress-text" title="50 10">50 10</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Progress render normal progress 1`] = `
|
|
||||||
<div class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default">
|
|
||||||
<div>
|
|
||||||
<div class="ant-progress-outer">
|
|
||||||
<div class="ant-progress-inner">
|
|
||||||
<div class="ant-progress-bg" style="width: 0%; height: 8px; border-radius: 100px;"></div>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div><span class="ant-progress-text" title="0%">0%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Progress render out-of-range progress 1`] = `
|
|
||||||
<div class="ant-progress ant-progress-line ant-progress-status-success ant-progress-show-info ant-progress-default">
|
|
||||||
<div>
|
|
||||||
<div class="ant-progress-outer">
|
|
||||||
<div class="ant-progress-inner">
|
|
||||||
<div class="ant-progress-bg" style="width: 100%; height: 8px; border-radius: 100px;"></div>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div><span class="ant-progress-text"><span role="img" aria-label="check-circle" class="anticon anticon-check-circle"><svg focusable="false" class="" data-icon="check-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path></svg></span></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Progress render out-of-range progress with info 1`] = `
|
|
||||||
<div class="ant-progress ant-progress-line ant-progress-status-success ant-progress-show-info ant-progress-default">
|
|
||||||
<div>
|
|
||||||
<div class="ant-progress-outer">
|
|
||||||
<div class="ant-progress-inner">
|
|
||||||
<div class="ant-progress-bg" style="width: 100%; height: 8px; border-radius: 100px;"></div>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div><span class="ant-progress-text"><span role="img" aria-label="check-circle" class="anticon anticon-check-circle"><svg focusable="false" class="" data-icon="check-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path></svg></span></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import { asyncExpect } from '@/tests/utils';
|
import { asyncExpect } from '@/tests/utils';
|
||||||
|
import { handleGradient, sortGradient } from '../Line';
|
||||||
import Progress from '..';
|
import Progress from '..';
|
||||||
|
import ProgressSteps from '../Steps';
|
||||||
|
|
||||||
describe('Progress', () => {
|
describe('Progress', () => {
|
||||||
it('successPercent should decide the progress status when it exists', async () => {
|
it('successPercent should decide the progress status when it exists', async () => {
|
||||||
const wrapper = mount(Progress, {
|
const wrapper = mount(Progress, {
|
||||||
props: {
|
props: {
|
||||||
percent: 100,
|
percent: 100,
|
||||||
successPercent: 50,
|
success: { percent: 50 },
|
||||||
},
|
},
|
||||||
sync: false,
|
sync: false,
|
||||||
});
|
});
|
||||||
|
@ -15,12 +17,12 @@ describe('Progress', () => {
|
||||||
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(0);
|
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.setProps({ percent: 50, successPercent: 100 });
|
wrapper.setProps({ percent: 50, success: { percent: 100 } });
|
||||||
await asyncExpect(() => {
|
await asyncExpect(() => {
|
||||||
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(1);
|
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.setProps({ percent: 100, successPercent: 0 });
|
wrapper.setProps({ percent: 100, success: { percent: 0 } });
|
||||||
await asyncExpect(() => {
|
await asyncExpect(() => {
|
||||||
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(0);
|
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
@ -51,7 +53,7 @@ describe('Progress', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render negetive progress', async () => {
|
it('render negative progress', async () => {
|
||||||
const wrapper = mount(Progress, {
|
const wrapper = mount(Progress, {
|
||||||
props: {
|
props: {
|
||||||
percent: -20,
|
percent: -20,
|
||||||
|
@ -63,11 +65,11 @@ describe('Progress', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render negetive successPercent', async () => {
|
it('render negative successPercent', async () => {
|
||||||
const wrapper = mount(Progress, {
|
const wrapper = mount(Progress, {
|
||||||
props: {
|
props: {
|
||||||
percent: 50,
|
percent: 50,
|
||||||
successPercent: -20,
|
success: { percent: -20 },
|
||||||
},
|
},
|
||||||
sync: false,
|
sync: false,
|
||||||
});
|
});
|
||||||
|
@ -76,7 +78,7 @@ describe('Progress', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render negetive successPercent', async () => {
|
it('render format', async () => {
|
||||||
const wrapper = mount(Progress, {
|
const wrapper = mount(Progress, {
|
||||||
props: {
|
props: {
|
||||||
percent: 50,
|
percent: 50,
|
||||||
|
@ -90,7 +92,7 @@ describe('Progress', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render format', async () => {
|
it('render strokeColor', async () => {
|
||||||
const wrapper = mount(Progress, {
|
const wrapper = mount(Progress, {
|
||||||
props: {
|
props: {
|
||||||
percent: 50,
|
percent: 50,
|
||||||
|
@ -102,10 +104,217 @@ describe('Progress', () => {
|
||||||
await asyncExpect(() => {
|
await asyncExpect(() => {
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
wrapper.setProps({
|
||||||
|
strokeColor: {
|
||||||
|
from: '#108ee9',
|
||||||
|
to: '#87d068',
|
||||||
|
},
|
||||||
|
type: 'line',
|
||||||
|
});
|
||||||
|
await asyncExpect(() => {
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
wrapper.setProps({
|
||||||
|
strokeColor: {
|
||||||
|
'0%': '#108ee9',
|
||||||
|
'100%': '#87d068',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await asyncExpect(() => {
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render normal progress', () => {
|
it('render normal progress', () => {
|
||||||
const wrapper = mount(Progress, { props: { status: 'normal' } });
|
const wrapper = mount(Progress, { props: { status: 'normal' } });
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('render trailColor progress', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress status="normal" trailColor="#ffffff" />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render successColor progress', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress percent={60} success={{ percent: 30, strokeColor: '#ffffff' }} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render dashboard zero gapDegree', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress type="dashboard" gapDegree={0} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render dashboard 295 gapDegree', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress type="dashboard" gapDegree={295} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render dashboard 296 gapDegree', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress type="dashboard" gapDegree={296} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get correct line-gradient', () => {
|
||||||
|
expect(handleGradient({ from: 'test', to: 'test' }).backgroundImage).toBe(
|
||||||
|
'linear-gradient(to right, test, test)',
|
||||||
|
);
|
||||||
|
expect(handleGradient({}).backgroundImage).toBe('linear-gradient(to right, #1890ff, #1890ff)');
|
||||||
|
expect(handleGradient({ from: 'test', to: 'test', '0%': 'test' }).backgroundImage).toBe(
|
||||||
|
'linear-gradient(to right, test 0%)',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sort gradients correctly', () => {
|
||||||
|
expect(sortGradient({ '10%': 'test10', '30%': 'test30', '20%': 'test20' })).toBe(
|
||||||
|
'test10 10%, test20 20%, test30 30%',
|
||||||
|
);
|
||||||
|
expect(sortGradient({ '10%': 'test10', '30%': 'test30', '20%': 'test20', dummy: 'test' })).toBe(
|
||||||
|
'test10 10%, test20 20%, test30 30%',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show success status when percent is 100', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress percent={100} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/ant-design/ant-design/issues/15950
|
||||||
|
it('should show success status when percent is 100 and status is undefined', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress percent={100} status={undefined} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/ant-design/ant-design/pull/15951#discussion_r273062969
|
||||||
|
it('should show success status when status is invalid', () => {
|
||||||
|
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress percent={100} status="invalid" />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.findAll('.ant-progress-status-success')).toHaveLength(1);
|
||||||
|
errorSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support steps', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress steps={3} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('steps should be changable', async () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress steps={5} percent={60} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item-active').length).toBe(3);
|
||||||
|
wrapper.setProps({ percent: 40 });
|
||||||
|
await asyncExpect(() => {
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item-active').length).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('steps should be changable when has strokeColor', async () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress steps={5} percent={60} strokeColor="#1890ff" />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item')[0].element.style.backgroundColor).toBe(
|
||||||
|
'rgb(24, 144, 255)',
|
||||||
|
);
|
||||||
|
wrapper.setProps({ percent: 40 });
|
||||||
|
await asyncExpect(() => {
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item')[2].element.style.backgroundColor).toBe('');
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item')[1].element.style.backgroundColor).toBe(
|
||||||
|
'rgb(24, 144, 255)',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('steps should support trailColor', () => {
|
||||||
|
const wrapper = mount(<Progress steps={5} percent={20} trailColor="#1890ee" />);
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item')[1].element.style.backgroundColor).toBe(
|
||||||
|
'rgb(24, 144, 238)',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display correct step', async () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <Progress steps={9} percent={22.22} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item-active').length).toBe(2);
|
||||||
|
wrapper.setProps({ percent: 33.33 });
|
||||||
|
await asyncExpect(() => {
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item-active').length).toBe(3);
|
||||||
|
});
|
||||||
|
wrapper.setProps({ percent: 44.44 });
|
||||||
|
await asyncExpect(() => {
|
||||||
|
expect(wrapper.findAll('.ant-progress-steps-item-active').length).toBe(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('steps should have default percent 0', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return <ProgressSteps />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should warning if use `progress` in success', () => {
|
||||||
|
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||||
|
mount(<Progress percent={60} success={{ progress: 30 }} />);
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
'Warning: [ant-design-vue: Progress] `success.progress` is deprecated. Please use `success.percent` instead.',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should warning if use `progress` in success in type Circle', () => {
|
||||||
|
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||||
|
mount({
|
||||||
|
render() {
|
||||||
|
return <Progress percent={60} success={{ progress: 30 }} type="circle" />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
'Warning: [ant-design-vue: Progress] `success.progress` is deprecated. Please use `success.percent` instead.',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
import type { ExtractPropTypes } from 'vue';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { Circle as VCCircle } from '../vc-progress';
|
|
||||||
import PropTypes from '../_util/vue-types';
|
|
||||||
import { validProgress } from './utils';
|
|
||||||
import { ProgressProps } from './props';
|
|
||||||
|
|
||||||
const CircleProps = {
|
|
||||||
...ProgressProps,
|
|
||||||
progressStatus: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
const statusColorMap: Record<string, string> = {
|
|
||||||
normal: '#108ee9',
|
|
||||||
exception: '#ff5500',
|
|
||||||
success: '#87d068',
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ICircleProps = ExtractPropTypes<typeof CircleProps>;
|
|
||||||
|
|
||||||
function getPercentage({ percent, successPercent }: ICircleProps) {
|
|
||||||
const ptg = validProgress(percent);
|
|
||||||
if (!successPercent) return ptg;
|
|
||||||
|
|
||||||
const successPtg = validProgress(successPercent);
|
|
||||||
return [successPercent, validProgress(ptg - successPtg)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStrokeColor({ progressStatus, successPercent, strokeColor }: ICircleProps) {
|
|
||||||
const color = strokeColor || statusColorMap[progressStatus];
|
|
||||||
if (!successPercent) return color;
|
|
||||||
return [statusColorMap.success, color];
|
|
||||||
}
|
|
||||||
|
|
||||||
const Circle = defineComponent({
|
|
||||||
props: CircleProps,
|
|
||||||
setup(props, { slots }) {
|
|
||||||
return () => {
|
|
||||||
const {
|
|
||||||
prefixCls,
|
|
||||||
width,
|
|
||||||
strokeWidth,
|
|
||||||
trailColor,
|
|
||||||
strokeLinecap,
|
|
||||||
gapPosition,
|
|
||||||
gapDegree,
|
|
||||||
type,
|
|
||||||
} = props;
|
|
||||||
const circleSize = width || 120;
|
|
||||||
const circleStyle = {
|
|
||||||
width: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
|
|
||||||
height: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
|
|
||||||
fontSize: `${circleSize * 0.15 + 6}px`,
|
|
||||||
};
|
|
||||||
const circleWidth = strokeWidth || 6;
|
|
||||||
const gapPos = gapPosition || (type === 'dashboard' && 'bottom') || 'top';
|
|
||||||
const gapDeg = gapDegree || (type === 'dashboard' && 75);
|
|
||||||
const strokeColor = getStrokeColor(props);
|
|
||||||
const isGradient = Object.prototype.toString.call(strokeColor) === '[object Object]';
|
|
||||||
|
|
||||||
const wrapperClassName = {
|
|
||||||
[`${prefixCls}-inner`]: true,
|
|
||||||
[`${prefixCls}-circle-gradient`]: isGradient,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={wrapperClassName} style={circleStyle}>
|
|
||||||
<VCCircle
|
|
||||||
percent={getPercentage(props)}
|
|
||||||
strokeWidth={circleWidth}
|
|
||||||
trailWidth={circleWidth}
|
|
||||||
strokeColor={strokeColor}
|
|
||||||
strokeLinecap={strokeLinecap}
|
|
||||||
trailColor={trailColor}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
gapDegree={gapDeg}
|
|
||||||
gapPosition={gapPos}
|
|
||||||
/>
|
|
||||||
{slots?.default()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Circle;
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Progress from './progress';
|
import Progress from './progress';
|
||||||
import { withInstall } from '../_util/type';
|
import { withInstall } from '../_util/type';
|
||||||
|
|
||||||
export { ProgressProps } from './props';
|
export type { ProgressProps } from './props';
|
||||||
|
|
||||||
export default withInstall(Progress);
|
export default withInstall(Progress);
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
import { validProgress } from './utils';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {
|
|
||||||
* '0%': '#afc163',
|
|
||||||
* '75%': '#009900',
|
|
||||||
* '50%': 'green', ====> '#afc163 0%, #66FF00 25%, #00CC00 50%, #009900 75%, #ffffff 100%'
|
|
||||||
* '25%': '#66FF00',
|
|
||||||
* '100%': '#ffffff'
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
export const sortGradient = gradients => {
|
|
||||||
let tempArr = [];
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
for (const [key, value] of Object.entries(gradients)) {
|
|
||||||
const formatKey = parseFloat(key.replace(/%/g, ''));
|
|
||||||
if (isNaN(formatKey)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
tempArr.push({
|
|
||||||
key: formatKey,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
tempArr = tempArr.sort((a, b) => a.key - b.key);
|
|
||||||
return tempArr.map(({ key, value }) => `${value} ${key}%`).join(', ');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {
|
|
||||||
* '0%': '#afc163',
|
|
||||||
* '25%': '#66FF00',
|
|
||||||
* '50%': '#00CC00', ====> linear-gradient(to right, #afc163 0%, #66FF00 25%,
|
|
||||||
* '75%': '#009900', #00CC00 50%, #009900 75%, #ffffff 100%)
|
|
||||||
* '100%': '#ffffff'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Then this man came to realize the truth:
|
|
||||||
* Besides six pence, there is the moon.
|
|
||||||
* Besides bread and butter, there is the bug.
|
|
||||||
* And...
|
|
||||||
* Besides women, there is the code.
|
|
||||||
*/
|
|
||||||
export const handleGradient = strokeColor => {
|
|
||||||
const { from = '#1890ff', to = '#1890ff', direction = 'to right', ...rest } = strokeColor;
|
|
||||||
if (Object.keys(rest).length !== 0) {
|
|
||||||
const sortedGradients = sortGradient(rest);
|
|
||||||
return { backgroundImage: `linear-gradient(${direction}, ${sortedGradients})` };
|
|
||||||
}
|
|
||||||
return { backgroundImage: `linear-gradient(${direction}, ${from}, ${to})` };
|
|
||||||
};
|
|
||||||
|
|
||||||
const Line = (_, { attrs, slots }) => {
|
|
||||||
const { prefixCls, percent, successPercent, strokeWidth, size, strokeColor, strokeLinecap } =
|
|
||||||
attrs;
|
|
||||||
let backgroundProps;
|
|
||||||
if (strokeColor && typeof strokeColor !== 'string') {
|
|
||||||
backgroundProps = handleGradient(strokeColor);
|
|
||||||
} else {
|
|
||||||
backgroundProps = {
|
|
||||||
background: strokeColor,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const percentStyle = {
|
|
||||||
width: `${validProgress(percent)}%`,
|
|
||||||
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
|
|
||||||
background: strokeColor,
|
|
||||||
borderRadius: strokeLinecap === 'square' ? 0 : '100px',
|
|
||||||
...backgroundProps,
|
|
||||||
};
|
|
||||||
const successPercentStyle = {
|
|
||||||
width: `${validProgress(successPercent)}%`,
|
|
||||||
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
|
|
||||||
borderRadius: strokeLinecap === 'square' ? 0 : '',
|
|
||||||
};
|
|
||||||
const successSegment =
|
|
||||||
successPercent !== undefined ? (
|
|
||||||
<div class={`${prefixCls}-success-bg`} style={successPercentStyle} />
|
|
||||||
) : null;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div class={`${prefixCls}-outer`}>
|
|
||||||
<div class={`${prefixCls}-inner`}>
|
|
||||||
<div class={`${prefixCls}-bg`} style={percentStyle} />
|
|
||||||
{successSegment}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{slots?.default()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Line;
|
|
|
@ -1,20 +1,22 @@
|
||||||
import { defineComponent, inject } from 'vue';
|
import type { VNodeChild } from 'vue';
|
||||||
import classNames from '../_util/classNames';
|
import { computed, defineComponent } from 'vue';
|
||||||
import { getOptionProps } from '../_util/props-util';
|
|
||||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
|
||||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||||
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
|
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
|
||||||
import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
|
import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
|
||||||
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
||||||
import Line from './line';
|
import Line from './Line';
|
||||||
import Circle from './circle';
|
import Circle from './Circle';
|
||||||
import { validProgress } from './utils';
|
import Steps from './Steps';
|
||||||
import { ProgressProps, ProgressStatuses } from './props';
|
import { getSuccessPercent, validProgress } from './utils';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import devWarning from '../vc-util/devWarning';
|
||||||
|
import type { ProgressStatusesType } from './props';
|
||||||
|
import { progressProps, progressStatuses } from './props';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AProgress',
|
name: 'AProgress',
|
||||||
props: initDefaultProps(ProgressProps, {
|
props: initDefaultProps(progressProps, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
percent: 0,
|
percent: 0,
|
||||||
showInfo: true,
|
showInfo: true,
|
||||||
|
@ -24,37 +26,49 @@ export default defineComponent({
|
||||||
gapDegree: 0,
|
gapDegree: 0,
|
||||||
strokeLinecap: 'round',
|
strokeLinecap: 'round',
|
||||||
}),
|
}),
|
||||||
setup() {
|
setup(props, { slots }) {
|
||||||
return {
|
const { prefixCls, direction } = useConfigInject('progress', props);
|
||||||
configProvider: inject('configProvider', defaultConfigProvider),
|
|
||||||
};
|
const classString = computed(() => {
|
||||||
},
|
const { type, showInfo, size } = props;
|
||||||
methods: {
|
const pre = prefixCls.value;
|
||||||
getPercentNumber() {
|
return {
|
||||||
const { successPercent, percent = 0 } = this.$props;
|
[pre]: true,
|
||||||
|
[`${pre}-${(type === 'dashboard' && 'circle') || type}`]: true,
|
||||||
|
[`${pre}-show-info`]: showInfo,
|
||||||
|
[`${pre}-${size}`]: size,
|
||||||
|
[`${pre}-rtl`]: direction.value === 'rtl',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPercentNumber = () => {
|
||||||
|
const { percent = 0 } = props;
|
||||||
|
const successPercent = getSuccessPercent(props.success, props.successPercent);
|
||||||
return parseInt(
|
return parseInt(
|
||||||
successPercent !== undefined ? successPercent.toString() : percent.toString(),
|
successPercent !== undefined ? successPercent.toString() : percent.toString(),
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
},
|
};
|
||||||
|
|
||||||
getProgressStatus() {
|
const getProgressStatus = () => {
|
||||||
const { status } = this.$props;
|
const { status } = props;
|
||||||
if (ProgressStatuses.indexOf(status) < 0 && this.getPercentNumber() >= 100) {
|
if (progressStatuses.indexOf(status) < 0 && getPercentNumber() >= 100) {
|
||||||
return 'success';
|
return 'success';
|
||||||
}
|
}
|
||||||
return status || 'normal';
|
return status || 'normal';
|
||||||
},
|
};
|
||||||
renderProcessInfo(prefixCls: string, progressStatus: typeof ProgressStatuses[number]) {
|
|
||||||
const { showInfo, format, type, percent, successPercent } = this.$props;
|
const renderProcessInfo = (prefixCls: string, progressStatus: ProgressStatusesType) => {
|
||||||
|
const { showInfo, format, type, percent } = props;
|
||||||
|
const successPercent = getSuccessPercent(props.success, props.successPercent);
|
||||||
if (!showInfo) return null;
|
if (!showInfo) return null;
|
||||||
|
|
||||||
let text;
|
let text: VNodeChild;
|
||||||
const textFormatter = format || this.$slots.format || (percentNumber => `${percentNumber}%`);
|
const textFormatter = format || slots?.format || (percentNumber => `${percentNumber}%`);
|
||||||
const isLineType = type === 'line';
|
const isLineType = type === 'line';
|
||||||
if (
|
if (
|
||||||
format ||
|
format ||
|
||||||
this.$slots.format ||
|
slots?.format ||
|
||||||
(progressStatus !== 'exception' && progressStatus !== 'success')
|
(progressStatus !== 'exception' && progressStatus !== 'success')
|
||||||
) {
|
) {
|
||||||
text = textFormatter(validProgress(percent), validProgress(successPercent));
|
text = textFormatter(validProgress(percent), validProgress(successPercent));
|
||||||
|
@ -68,44 +82,50 @@ export default defineComponent({
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const props = getOptionProps(this);
|
|
||||||
const { prefixCls: customizePrefixCls, size, type, showInfo } = props;
|
|
||||||
const { getPrefixCls } = this.configProvider;
|
|
||||||
const prefixCls = getPrefixCls('progress', customizePrefixCls);
|
|
||||||
const progressStatus = this.getProgressStatus();
|
|
||||||
const progressInfo = this.renderProcessInfo(prefixCls, progressStatus);
|
|
||||||
|
|
||||||
let progress;
|
|
||||||
|
|
||||||
// Render progress shape
|
|
||||||
if (type === 'line') {
|
|
||||||
const lineProps = {
|
|
||||||
...props,
|
|
||||||
prefixCls,
|
|
||||||
};
|
|
||||||
progress = <Line {...lineProps}>{progressInfo}</Line>;
|
|
||||||
} else if (type === 'circle' || type === 'dashboard') {
|
|
||||||
const circleProps = {
|
|
||||||
...props,
|
|
||||||
prefixCls,
|
|
||||||
progressStatus,
|
|
||||||
};
|
|
||||||
progress = <Circle {...circleProps}>{progressInfo}</Circle>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const classString = classNames(prefixCls, {
|
|
||||||
[`${prefixCls}-${(type === 'dashboard' && 'circle') || type}`]: true,
|
|
||||||
[`${prefixCls}-status-${progressStatus}`]: true,
|
|
||||||
[`${prefixCls}-show-info`]: showInfo,
|
|
||||||
[`${prefixCls}-${size}`]: size,
|
|
||||||
});
|
|
||||||
|
|
||||||
const progressProps = {
|
|
||||||
class: classString,
|
|
||||||
};
|
};
|
||||||
return <div {...progressProps}>{progress}</div>;
|
|
||||||
|
return () => {
|
||||||
|
const { type, steps, strokeColor } = props;
|
||||||
|
const progressStatus = getProgressStatus();
|
||||||
|
const progressInfo = renderProcessInfo(prefixCls.value, progressStatus);
|
||||||
|
|
||||||
|
devWarning(
|
||||||
|
props.successPercent == undefined,
|
||||||
|
'Progress',
|
||||||
|
'`successPercent` is deprecated. Please use `success.percent` instead.',
|
||||||
|
);
|
||||||
|
|
||||||
|
let progress: VNodeChild;
|
||||||
|
// Render progress shape
|
||||||
|
if (type === 'line') {
|
||||||
|
progress = steps ? (
|
||||||
|
<Steps
|
||||||
|
{...props}
|
||||||
|
strokeColor={typeof strokeColor === 'string' ? strokeColor : undefined}
|
||||||
|
prefixCls={prefixCls.value}
|
||||||
|
steps={steps}
|
||||||
|
>
|
||||||
|
{progressInfo}
|
||||||
|
</Steps>
|
||||||
|
) : (
|
||||||
|
<Line {...props} prefixCls={prefixCls.value}>
|
||||||
|
{progressInfo}
|
||||||
|
</Line>
|
||||||
|
);
|
||||||
|
} else if (type === 'circle' || type === 'dashboard') {
|
||||||
|
progress = (
|
||||||
|
<Circle {...props} prefixCls={prefixCls.value}>
|
||||||
|
{progressInfo}
|
||||||
|
</Circle>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const classNames = {
|
||||||
|
...classString.value,
|
||||||
|
[`${prefixCls.value}-status-${progressStatus}`]: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return <div class={classNames}>{progress}</div>;
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,24 +1,48 @@
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { tuple } from '../_util/type';
|
import { tuple } from '../_util/type';
|
||||||
|
import type { PropType, VNodeChild, ExtractPropTypes } from 'vue';
|
||||||
|
|
||||||
export const ProgressStatuses = tuple('normal', 'exception', 'active', 'success');
|
export const progressStatuses = tuple('normal', 'exception', 'active', 'success');
|
||||||
export const ProgressType = PropTypes.oneOf(tuple('line', 'circle', 'dashboard'));
|
export type ProgressStatusesType = typeof progressStatuses[number];
|
||||||
export const ProgressSize = PropTypes.oneOf(tuple('default', 'small'));
|
const ProgressType = tuple('line', 'circle', 'dashboard');
|
||||||
|
export type ProgressType = typeof ProgressType[number];
|
||||||
|
const ProgressSize = tuple('default', 'small');
|
||||||
|
export type ProgressSize = typeof ProgressSize[number];
|
||||||
|
export type StringGradients = { [percentage: string]: string };
|
||||||
|
type FromToGradients = { from: string; to: string };
|
||||||
|
export type ProgressGradient = { direction?: string } & (StringGradients | FromToGradients);
|
||||||
|
|
||||||
export const ProgressProps = {
|
export interface SuccessProps {
|
||||||
|
percent?: number;
|
||||||
|
/** @deprecated Use `percent` instead */
|
||||||
|
progress?: number;
|
||||||
|
strokeColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const progressProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
type: ProgressType,
|
type: PropTypes.oneOf(ProgressType),
|
||||||
percent: PropTypes.number,
|
percent: PropTypes.number,
|
||||||
successPercent: PropTypes.number,
|
format: { type: Function as PropType<(percent?: number, successPercent?: number) => VNodeChild> },
|
||||||
format: PropTypes.func,
|
status: PropTypes.oneOf(progressStatuses),
|
||||||
status: PropTypes.oneOf(ProgressStatuses),
|
|
||||||
showInfo: PropTypes.looseBool,
|
showInfo: PropTypes.looseBool,
|
||||||
strokeWidth: PropTypes.number,
|
strokeWidth: PropTypes.number,
|
||||||
strokeLinecap: PropTypes.oneOf(['butt', 'round', 'square']),
|
strokeLinecap: PropTypes.oneOf(tuple('butt', 'round', 'square')),
|
||||||
strokeColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
strokeColor: {
|
||||||
|
type: [String, Object] as PropType<string | ProgressGradient>,
|
||||||
|
},
|
||||||
trailColor: PropTypes.string,
|
trailColor: PropTypes.string,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
|
success: {
|
||||||
|
type: Object as PropType<SuccessProps>,
|
||||||
|
default: (): SuccessProps => ({}),
|
||||||
|
},
|
||||||
gapDegree: PropTypes.number,
|
gapDegree: PropTypes.number,
|
||||||
gapPosition: PropTypes.oneOf(tuple('top', 'bottom', 'left', 'right')),
|
gapPosition: PropTypes.oneOf(tuple('top', 'bottom', 'left', 'right')),
|
||||||
size: ProgressSize,
|
size: PropTypes.oneOf(ProgressSize),
|
||||||
|
steps: PropTypes.number,
|
||||||
|
/** @deprecated Use `success` instead */
|
||||||
|
successPercent: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ProgressProps = Partial<ExtractPropTypes<typeof progressProps>>;
|
||||||
|
|
|
@ -14,6 +14,26 @@
|
||||||
font-size: @font-size-base;
|
font-size: @font-size-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-steps {
|
||||||
|
display: inline-block;
|
||||||
|
&-outer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
&-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-width: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
background: @progress-steps-item-bg;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&-active {
|
||||||
|
background: @progress-default-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-small&-line,
|
&-small&-line,
|
||||||
&-small&-line &-text .@{iconfont-css-prefix} {
|
&-small&-line &-text .@{iconfont-css-prefix} {
|
||||||
font-size: @font-size-sm;
|
font-size: @font-size-sm;
|
||||||
|
@ -73,8 +93,8 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 2em;
|
width: 2em;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
color: @text-color-secondary;
|
color: @progress-info-text-color;
|
||||||
font-size: 1em;
|
font-size: @progress-text-font-size;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
@ -144,6 +164,7 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: @progress-text-color;
|
color: @progress-text-color;
|
||||||
|
font-size: @progress-circle-text-font-size;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -180,3 +201,5 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@import './rtl';
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
@import '../../style/themes/index';
|
||||||
|
@import '../../style/mixins/index';
|
||||||
|
|
||||||
|
@progress-prefix-cls: ~'@{ant-prefix}-progress';
|
||||||
|
|
||||||
|
.@{progress-prefix-cls} {
|
||||||
|
&-rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-outer {
|
||||||
|
.@{progress-prefix-cls}-show-info & {
|
||||||
|
.@{progress-prefix-cls}-rtl& {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: ~'calc(-2em - 8px)';
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: ~'calc(2em + 8px)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-success-bg {
|
||||||
|
.@{progress-prefix-cls}-rtl & {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-line &-text,
|
||||||
|
&-steps &-text {
|
||||||
|
.@{progress-prefix-cls}-rtl& {
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-left: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
export function validProgress(progress?: number) {
|
import devWarning from '../vc-util/devWarning';
|
||||||
|
import type { ProgressProps } from './props';
|
||||||
|
|
||||||
|
export function validProgress(progress: number | undefined) {
|
||||||
if (!progress || progress < 0) {
|
if (!progress || progress < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -7,3 +10,23 @@ export function validProgress(progress?: number) {
|
||||||
}
|
}
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSuccessPercent(
|
||||||
|
success?: ProgressProps['success'],
|
||||||
|
successPercent?: ProgressProps['successPercent'],
|
||||||
|
) {
|
||||||
|
let percent = successPercent;
|
||||||
|
/** @deprecated Use `percent` instead */
|
||||||
|
if (success && 'progress' in success) {
|
||||||
|
devWarning(
|
||||||
|
false,
|
||||||
|
'Progress',
|
||||||
|
'`success.progress` is deprecated. Please use `success.percent` instead.',
|
||||||
|
);
|
||||||
|
percent = success.progress;
|
||||||
|
}
|
||||||
|
if (success && 'percent' in success) {
|
||||||
|
percent = success.percent;
|
||||||
|
}
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
|
@ -496,9 +496,12 @@
|
||||||
// --
|
// --
|
||||||
@progress-default-color: @processing-color;
|
@progress-default-color: @processing-color;
|
||||||
@progress-remaining-color: @background-color-base;
|
@progress-remaining-color: @background-color-base;
|
||||||
@progress-text-color: @text-color;
|
@progress-info-text-color: @progress-text-color;
|
||||||
@progress-radius: 100px;
|
@progress-radius: 100px;
|
||||||
|
@progress-steps-item-bg: #f3f3f3;
|
||||||
|
@progress-text-font-size: 1em;
|
||||||
|
@progress-text-color: @text-color; // This is for circle text color, should be renamed better
|
||||||
|
@progress-circle-text-font-size: 1em;
|
||||||
// Menu
|
// Menu
|
||||||
// ---
|
// ---
|
||||||
@menu-inline-toplevel-item-height: 40px;
|
@menu-inline-toplevel-item-height: 40px;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// based on rc-progress 2.5.2
|
// based on rc-progress 2.5.2
|
||||||
import Progress, { Line, Circle } from './src/';
|
import Progress, { Line, Circle } from './src';
|
||||||
|
|
||||||
export { Line, Circle };
|
export { Line, Circle };
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
import PropTypes, { withUndefined } from '../../_util/vue-types';
|
|
||||||
import { initDefaultProps } from '../../_util/props-util';
|
|
||||||
import enhancer from './enhancer';
|
|
||||||
import { propTypes, defaultProps } from './types';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
const circlePropTypes = {
|
|
||||||
...propTypes,
|
|
||||||
gapPosition: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
|
|
||||||
gapDegree: withUndefined(
|
|
||||||
PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.looseBool]),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
const circleDefaultProps = {
|
|
||||||
...defaultProps,
|
|
||||||
gapPosition: 'top',
|
|
||||||
};
|
|
||||||
|
|
||||||
let gradientSeed = 0;
|
|
||||||
|
|
||||||
function stripPercentToNumber(percent) {
|
|
||||||
return +percent.replace('%', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function toArray(symArray) {
|
|
||||||
return Array.isArray(symArray) ? symArray : [symArray];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPathStyles(offset, percent, strokeColor, strokeWidth, gapDegree = 0, gapPosition) {
|
|
||||||
const radius = 50 - strokeWidth / 2;
|
|
||||||
let beginPositionX = 0;
|
|
||||||
let beginPositionY = -radius;
|
|
||||||
let endPositionX = 0;
|
|
||||||
let endPositionY = -2 * radius;
|
|
||||||
switch (gapPosition) {
|
|
||||||
case 'left':
|
|
||||||
beginPositionX = -radius;
|
|
||||||
beginPositionY = 0;
|
|
||||||
endPositionX = 2 * radius;
|
|
||||||
endPositionY = 0;
|
|
||||||
break;
|
|
||||||
case 'right':
|
|
||||||
beginPositionX = radius;
|
|
||||||
beginPositionY = 0;
|
|
||||||
endPositionX = -2 * radius;
|
|
||||||
endPositionY = 0;
|
|
||||||
break;
|
|
||||||
case 'bottom':
|
|
||||||
beginPositionY = radius;
|
|
||||||
endPositionY = 2 * radius;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
const pathString = `M 50,50 m ${beginPositionX},${beginPositionY}
|
|
||||||
a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY}
|
|
||||||
a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`;
|
|
||||||
const len = Math.PI * 2 * radius;
|
|
||||||
|
|
||||||
const pathStyle = {
|
|
||||||
stroke: strokeColor,
|
|
||||||
strokeDasharray: `${(percent / 100) * (len - gapDegree)}px ${len}px`,
|
|
||||||
strokeDashoffset: `-${gapDegree / 2 + (offset / 100) * (len - gapDegree)}px`,
|
|
||||||
transition:
|
|
||||||
'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s', // eslint-disable-line
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
pathString,
|
|
||||||
pathStyle,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const Circle = defineComponent({
|
|
||||||
name: 'Circle',
|
|
||||||
props: initDefaultProps(circlePropTypes, circleDefaultProps),
|
|
||||||
created() {
|
|
||||||
this.paths = {};
|
|
||||||
this.gradientId = gradientSeed;
|
|
||||||
gradientSeed += 1;
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getStokeList() {
|
|
||||||
const {
|
|
||||||
prefixCls,
|
|
||||||
percent,
|
|
||||||
strokeColor,
|
|
||||||
strokeWidth,
|
|
||||||
strokeLinecap,
|
|
||||||
gapDegree,
|
|
||||||
gapPosition,
|
|
||||||
} = this.$props;
|
|
||||||
const percentList = toArray(percent);
|
|
||||||
const strokeColorList = toArray(strokeColor);
|
|
||||||
|
|
||||||
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})`
|
|
||||||
: '';
|
|
||||||
const { pathString, pathStyle } = getPathStyles(
|
|
||||||
stackPtg,
|
|
||||||
ptg,
|
|
||||||
color,
|
|
||||||
strokeWidth,
|
|
||||||
gapDegree,
|
|
||||||
gapPosition,
|
|
||||||
);
|
|
||||||
|
|
||||||
stackPtg += ptg;
|
|
||||||
|
|
||||||
const pathProps = {
|
|
||||||
key: index,
|
|
||||||
d: pathString,
|
|
||||||
stroke,
|
|
||||||
'stroke-linecap': strokeLinecap,
|
|
||||||
'stroke-width': strokeWidth,
|
|
||||||
opacity: ptg === 0 ? 0 : 1,
|
|
||||||
'fill-opacity': '0',
|
|
||||||
class: `${prefixCls}-circle-path`,
|
|
||||||
style: pathStyle,
|
|
||||||
};
|
|
||||||
return <path ref={c => (this.paths[index] = c)} {...pathProps} />;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
prefixCls,
|
|
||||||
strokeWidth,
|
|
||||||
trailWidth,
|
|
||||||
gapDegree,
|
|
||||||
gapPosition,
|
|
||||||
trailColor,
|
|
||||||
strokeLinecap,
|
|
||||||
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]',
|
|
||||||
);
|
|
||||||
const pathFirst = {
|
|
||||||
d: pathString,
|
|
||||||
stroke: trailColor,
|
|
||||||
'stroke-linecap': strokeLinecap,
|
|
||||||
'stroke-width': trailWidth || strokeWidth,
|
|
||||||
'fill-opacity': '0',
|
|
||||||
class: `${prefixCls}-circle-trail`,
|
|
||||||
style: pathStyle,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<svg class={`${prefixCls}-circle`} viewBox="0 0 100 100" {...restProps}>
|
|
||||||
{gradient && (
|
|
||||||
<defs>
|
|
||||||
<linearGradient
|
|
||||||
id={`${prefixCls}-gradient-${this.gradientId}`}
|
|
||||||
x1="100%"
|
|
||||||
y1="0%"
|
|
||||||
x2="0%"
|
|
||||||
y2="0%"
|
|
||||||
>
|
|
||||||
{Object.keys(gradient)
|
|
||||||
.sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b))
|
|
||||||
.map((key, index) => (
|
|
||||||
<stop key={index} offset={key} stop-color={gradient[key]} />
|
|
||||||
))}
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
)}
|
|
||||||
<path {...pathFirst} />
|
|
||||||
{this.getStokeList().reverse()}
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default enhancer(Circle);
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
import { useTransitionDuration, defaultProps } from './common';
|
||||||
|
import { propTypes, GapPositionType } from './types';
|
||||||
|
import { computed, defineComponent, ref } from 'vue';
|
||||||
|
import initDefaultProps from '../../_util/props-util/initDefaultProps';
|
||||||
|
|
||||||
|
let gradientSeed = 0;
|
||||||
|
|
||||||
|
function stripPercentToNumber(percent: string) {
|
||||||
|
return +percent.replace('%', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArray(value: any) {
|
||||||
|
return Array.isArray(value) ? value : [value];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPathStyles(
|
||||||
|
offset: number,
|
||||||
|
percent: number,
|
||||||
|
strokeColor: string,
|
||||||
|
strokeWidth: number,
|
||||||
|
gapDegree = 0,
|
||||||
|
gapPosition: GapPositionType,
|
||||||
|
) {
|
||||||
|
const radius = 50 - strokeWidth / 2;
|
||||||
|
let beginPositionX = 0;
|
||||||
|
let beginPositionY = -radius;
|
||||||
|
let endPositionX = 0;
|
||||||
|
let endPositionY = -2 * radius;
|
||||||
|
switch (gapPosition) {
|
||||||
|
case 'left':
|
||||||
|
beginPositionX = -radius;
|
||||||
|
beginPositionY = 0;
|
||||||
|
endPositionX = 2 * radius;
|
||||||
|
endPositionY = 0;
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
beginPositionX = radius;
|
||||||
|
beginPositionY = 0;
|
||||||
|
endPositionX = -2 * radius;
|
||||||
|
endPositionY = 0;
|
||||||
|
break;
|
||||||
|
case 'bottom':
|
||||||
|
beginPositionY = radius;
|
||||||
|
endPositionY = 2 * radius;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
const pathString = `M 50,50 m ${beginPositionX},${beginPositionY}
|
||||||
|
a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY}
|
||||||
|
a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`;
|
||||||
|
const len = Math.PI * 2 * radius;
|
||||||
|
|
||||||
|
const pathStyle = {
|
||||||
|
stroke: strokeColor,
|
||||||
|
strokeDasharray: `${(percent / 100) * (len - gapDegree)}px ${len}px`,
|
||||||
|
strokeDashoffset: `-${gapDegree / 2 + (offset / 100) * (len - gapDegree)}px`,
|
||||||
|
transition:
|
||||||
|
'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s', // eslint-disable-line
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
pathString,
|
||||||
|
pathStyle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'VCCircle',
|
||||||
|
props: initDefaultProps(propTypes, defaultProps),
|
||||||
|
setup(props) {
|
||||||
|
gradientSeed += 1;
|
||||||
|
const gradientId = ref(gradientSeed);
|
||||||
|
const percentList = computed(() => toArray(props.percent));
|
||||||
|
const strokeColorList = computed(() => toArray(props.strokeColor));
|
||||||
|
|
||||||
|
const paths = useTransitionDuration(percentList);
|
||||||
|
|
||||||
|
const getStokeList = () => {
|
||||||
|
const { prefixCls, strokeWidth, strokeLinecap, gapDegree, gapPosition } = props;
|
||||||
|
|
||||||
|
let stackPtg = 0;
|
||||||
|
return percentList.value.map((ptg, index) => {
|
||||||
|
const color =
|
||||||
|
strokeColorList.value[index] || strokeColorList.value[strokeColorList.value.length - 1];
|
||||||
|
const stroke =
|
||||||
|
Object.prototype.toString.call(color) === '[object Object]'
|
||||||
|
? `url(#${prefixCls}-gradient-${gradientId.value})`
|
||||||
|
: '';
|
||||||
|
const { pathString, pathStyle } = getPathStyles(
|
||||||
|
stackPtg,
|
||||||
|
ptg,
|
||||||
|
color,
|
||||||
|
strokeWidth,
|
||||||
|
gapDegree,
|
||||||
|
gapPosition,
|
||||||
|
);
|
||||||
|
|
||||||
|
stackPtg += ptg;
|
||||||
|
|
||||||
|
const pathProps = {
|
||||||
|
key: index,
|
||||||
|
d: pathString,
|
||||||
|
stroke,
|
||||||
|
'stroke-linecap': strokeLinecap,
|
||||||
|
'stroke-width': strokeWidth,
|
||||||
|
opacity: ptg === 0 ? 0 : 1,
|
||||||
|
'fill-opacity': '0',
|
||||||
|
class: `${prefixCls}-circle-path`,
|
||||||
|
style: pathStyle,
|
||||||
|
};
|
||||||
|
return <path ref={c => (paths.value[index].value = c)} {...pathProps} />;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
strokeWidth,
|
||||||
|
trailWidth,
|
||||||
|
gapDegree,
|
||||||
|
gapPosition,
|
||||||
|
trailColor,
|
||||||
|
strokeLinecap,
|
||||||
|
strokeColor,
|
||||||
|
...restProps
|
||||||
|
} = props;
|
||||||
|
const { pathString, pathStyle } = getPathStyles(
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
trailColor,
|
||||||
|
strokeWidth,
|
||||||
|
gapDegree,
|
||||||
|
gapPosition,
|
||||||
|
);
|
||||||
|
delete restProps.percent;
|
||||||
|
const gradient = strokeColorList.value.find(
|
||||||
|
color => Object.prototype.toString.call(color) === '[object Object]',
|
||||||
|
);
|
||||||
|
const pathFirst = {
|
||||||
|
d: pathString,
|
||||||
|
stroke: trailColor,
|
||||||
|
'stroke-linecap': strokeLinecap,
|
||||||
|
'stroke-width': trailWidth || strokeWidth,
|
||||||
|
'fill-opacity': '0',
|
||||||
|
class: `${prefixCls}-circle-trail`,
|
||||||
|
style: pathStyle,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg class={`${prefixCls}-circle`} viewBox="0 0 100 100" {...restProps}>
|
||||||
|
{gradient && (
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id={`${prefixCls}-gradient-${gradientId.value}`}
|
||||||
|
x1="100%"
|
||||||
|
y1="0%"
|
||||||
|
x2="0%"
|
||||||
|
y2="0%"
|
||||||
|
>
|
||||||
|
{Object.keys(gradient)
|
||||||
|
.sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b))
|
||||||
|
.map((key, index) => (
|
||||||
|
<stop key={index} offset={key} stop-color={gradient[key]} />
|
||||||
|
))}
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
)}
|
||||||
|
<path {...pathFirst} />
|
||||||
|
{getStokeList().reverse()}
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,84 +0,0 @@
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { initDefaultProps } from '../../_util/props-util';
|
|
||||||
import enhancer from './enhancer';
|
|
||||||
import { propTypes, defaultProps } from './types';
|
|
||||||
|
|
||||||
const Line = defineComponent({
|
|
||||||
name: 'Line',
|
|
||||||
props: initDefaultProps(propTypes, defaultProps),
|
|
||||||
created() {
|
|
||||||
this.paths = {};
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
percent,
|
|
||||||
prefixCls,
|
|
||||||
strokeColor,
|
|
||||||
strokeLinecap,
|
|
||||||
strokeWidth,
|
|
||||||
trailColor,
|
|
||||||
trailWidth,
|
|
||||||
transition,
|
|
||||||
...restProps
|
|
||||||
} = this.$props;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
const pathFirst = {
|
|
||||||
d: pathString,
|
|
||||||
'stroke-linecap': strokeLinecap,
|
|
||||||
stroke: trailColor,
|
|
||||||
'stroke-width': trailWidth || strokeWidth,
|
|
||||||
'fill-opacity': '0',
|
|
||||||
class: `${prefixCls}-line-trail`,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
class={`${prefixCls}-line`}
|
|
||||||
viewBox={viewBoxString}
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
{...restProps}
|
|
||||||
>
|
|
||||||
<path {...pathFirst} />
|
|
||||||
{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;
|
|
||||||
|
|
||||||
const pathProps = {
|
|
||||||
key: index,
|
|
||||||
d: pathString,
|
|
||||||
'stroke-linecap': strokeLinecap,
|
|
||||||
stroke: color,
|
|
||||||
'stroke-width': strokeWidth,
|
|
||||||
'fill-opacity': '0',
|
|
||||||
class: `${prefixCls}-line-path`,
|
|
||||||
style: pathStyle,
|
|
||||||
};
|
|
||||||
|
|
||||||
return <path ref={c => (this.paths[index] = c)} {...pathProps} />;
|
|
||||||
})}
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default enhancer(Line);
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
import { computed, defineComponent } from 'vue';
|
||||||
|
import initDefaultProps from '../../_util/props-util/initDefaultProps';
|
||||||
|
import { useTransitionDuration, defaultProps } from './common';
|
||||||
|
import { propTypes } from './types';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Line',
|
||||||
|
props: initDefaultProps(propTypes, defaultProps),
|
||||||
|
setup(props) {
|
||||||
|
const percentList = computed(() => {
|
||||||
|
const { percent } = props;
|
||||||
|
return Array.isArray(percent) ? percent : [percent];
|
||||||
|
});
|
||||||
|
|
||||||
|
const strokeColorList = computed(() => {
|
||||||
|
const { strokeColor } = props;
|
||||||
|
return Array.isArray(strokeColor) ? strokeColor : [strokeColor];
|
||||||
|
});
|
||||||
|
|
||||||
|
const paths = useTransitionDuration(percentList);
|
||||||
|
const center = computed(() => props.strokeWidth / 2);
|
||||||
|
const right = computed(() => 100 - props.strokeWidth / 2);
|
||||||
|
|
||||||
|
const pathString = computed(
|
||||||
|
() => `M ${props.strokeLinecap === 'round' ? center.value : 0},${center.value}
|
||||||
|
L ${props.strokeLinecap === 'round' ? right.value : 100},${center.value}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const viewBoxString = computed(() => `0 0 100 ${props.strokeWidth}`);
|
||||||
|
|
||||||
|
const pathFirst = computed(() => ({
|
||||||
|
d: pathString.value,
|
||||||
|
'stroke-linecap': props.strokeLinecap,
|
||||||
|
stroke: props.trailColor,
|
||||||
|
'stroke-width': props.trailWidth || props.strokeWidth,
|
||||||
|
'fill-opacity': '0',
|
||||||
|
class: `${props.prefixCls}-line-trail`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
percent,
|
||||||
|
prefixCls,
|
||||||
|
strokeColor,
|
||||||
|
strokeLinecap,
|
||||||
|
strokeWidth,
|
||||||
|
trailColor,
|
||||||
|
trailWidth,
|
||||||
|
transition,
|
||||||
|
...restProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
delete restProps.gapPosition;
|
||||||
|
|
||||||
|
let stackPtg = 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
class={`${prefixCls}-line`}
|
||||||
|
viewBox={viewBoxString.value}
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
<path {...pathFirst.value} />
|
||||||
|
{percentList.value.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.value[index] ||
|
||||||
|
strokeColorList.value[strokeColorList.value.length - 1];
|
||||||
|
|
||||||
|
stackPtg += ptg;
|
||||||
|
|
||||||
|
const pathProps = {
|
||||||
|
key: index,
|
||||||
|
d: pathString.value,
|
||||||
|
'stroke-linecap': strokeLinecap,
|
||||||
|
stroke: color as string,
|
||||||
|
'stroke-width': strokeWidth,
|
||||||
|
'fill-opacity': '0',
|
||||||
|
class: `${prefixCls}-line-path`,
|
||||||
|
style: pathStyle,
|
||||||
|
};
|
||||||
|
|
||||||
|
return <path ref={c => (paths.value[index].value = c)} {...pathProps} />;
|
||||||
|
})}
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,43 @@
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
import { ref, onUpdated, computed } from 'vue';
|
||||||
|
import type { ProgressProps } from './types';
|
||||||
|
|
||||||
|
export const defaultProps: Partial<ProgressProps> = {
|
||||||
|
percent: 0,
|
||||||
|
prefixCls: 'vc-progress',
|
||||||
|
strokeColor: '#2db7f5',
|
||||||
|
strokeLinecap: 'round',
|
||||||
|
strokeWidth: 1,
|
||||||
|
trailColor: '#D9D9D9',
|
||||||
|
trailWidth: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTransitionDuration = (percentList: Ref<number[]>) => {
|
||||||
|
const paths = computed(() => percentList.value.map(() => ref()));
|
||||||
|
const prevTimeStamp = ref(null);
|
||||||
|
|
||||||
|
onUpdated(() => {
|
||||||
|
const now = Date.now();
|
||||||
|
let updated = false;
|
||||||
|
|
||||||
|
Object.keys(paths.value).forEach(key => {
|
||||||
|
const path = paths.value[key].value;
|
||||||
|
if (!path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updated = true;
|
||||||
|
const pathStyle = path.style;
|
||||||
|
pathStyle.transitionDuration = '.3s, .3s, .3s, .06s';
|
||||||
|
|
||||||
|
if (prevTimeStamp.value && now - prevTimeStamp.value < 100) {
|
||||||
|
pathStyle.transitionDuration = '0s, 0s';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
|
prevTimeStamp.value = Date.now();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
};
|
|
@ -1,30 +0,0 @@
|
||||||
function enhancer(Component) {
|
|
||||||
return {
|
|
||||||
...Component,
|
|
||||||
updated() {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default enhancer;
|
|
|
@ -1,7 +1,8 @@
|
||||||
import Line from './Line';
|
import Line from './Line';
|
||||||
import Circle from './Circle';
|
import Circle from './Circle';
|
||||||
|
import type { ProgressProps } from './types';
|
||||||
|
|
||||||
export { Line, Circle };
|
export { Line, Circle, ProgressProps };
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Line,
|
Line,
|
|
@ -1,30 +0,0 @@
|
||||||
import PropTypes from '../../_util/vue-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,
|
|
||||||
};
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import type { PropType, ExtractPropTypes } from 'vue';
|
||||||
|
import PropTypes from '../../_util/vue-types';
|
||||||
|
|
||||||
|
export type StrokeColorType = string | string[] | object;
|
||||||
|
|
||||||
|
export type GapPositionType = 'top' | 'right' | 'bottom' | 'left';
|
||||||
|
|
||||||
|
export type StrokeLinecapType = 'round' | 'butt' | 'square';
|
||||||
|
|
||||||
|
export const propTypes = {
|
||||||
|
gapDegree: PropTypes.number,
|
||||||
|
gapPosition: {
|
||||||
|
type: String as PropType<GapPositionType>,
|
||||||
|
},
|
||||||
|
percent: {
|
||||||
|
type: [Array, Number] as PropType<number | number[]>,
|
||||||
|
},
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
strokeColor: {
|
||||||
|
type: [Object, String, Array] as PropType<StrokeColorType>,
|
||||||
|
},
|
||||||
|
strokeLinecap: {
|
||||||
|
type: String as PropType<StrokeLinecapType>,
|
||||||
|
},
|
||||||
|
strokeWidth: PropTypes.number,
|
||||||
|
trailColor: PropTypes.string,
|
||||||
|
trailWidth: PropTypes.number,
|
||||||
|
transition: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProgressProps = Partial<ExtractPropTypes<typeof propTypes>>;
|
Loading…
Reference in New Issue