refactor: progress #6234

pull/6236/head
tangjinzhou 2023-02-07 11:08:42 +08:00
parent 2c1afa5e72
commit a40816880a
8 changed files with 98 additions and 82 deletions

View File

@ -55,6 +55,10 @@ export function booleanType(defaultVal?: any) {
return { type: Boolean, default: defaultVal as boolean }; return { type: Boolean, default: defaultVal as boolean };
} }
export function functionType<T = () => {}>(defaultVal?: any) {
return { type: Function as PropType<T>, default: defaultVal as T };
}
export function anyType<T = any>() { export function anyType<T = any>() {
return { validator: () => true } as unknown as { type: PropType<T> }; return { validator: () => true } as unknown as { type: PropType<T> };
} }

View File

@ -1,31 +1,26 @@
import type { CSSProperties } from 'vue'; import type { CSSProperties } from 'vue';
import { computed, defineComponent } from 'vue'; import { computed, defineComponent } from 'vue';
import { presetPrimaryColors } from '@ant-design/colors';
import { Circle as VCCircle } from '../vc-progress'; import { Circle as VCCircle } from '../vc-progress';
import { getSuccessPercent, validProgress } from './utils'; import { getPercentage, getStrokeColor } from './utils';
import type { ProgressProps } from './props'; import type { ProgressProps } from './props';
import { progressProps } from './props'; import { progressProps } from './props';
import { initDefaultProps } from '../_util/props-util';
import Tooltip from '../tooltip';
export type CircleProps = ProgressProps; export type CircleProps = ProgressProps;
function getPercentage({ percent, success, successPercent }: CircleProps) { const CIRCLE_MIN_STROKE_WIDTH = 3;
const realSuccessPercent = validProgress(getSuccessPercent({ success, successPercent }));
return [realSuccessPercent, validProgress(validProgress(percent) - realSuccessPercent)];
}
function getStrokeColor({ const getMinPercent = (width: number): number => (CIRCLE_MIN_STROKE_WIDTH / width) * 100;
success = {},
strokeColor,
}: Partial<CircleProps>): (string | Record<string, string>)[] {
const { strokeColor: successColor } = success;
return [successColor || presetPrimaryColors.green, strokeColor || null!];
}
export default defineComponent({ export default defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
name: 'Circle', name: 'Circle',
inheritAttrs: false, inheritAttrs: false,
props: progressProps(), props: initDefaultProps(progressProps(), {
width: 120,
trailColor: null as unknown as string,
}),
setup(props, { slots }) { setup(props, { slots }) {
const gapDeg = computed(() => { const gapDeg = computed(() => {
// Support gapDeg = 0 when type = 'dashboard' // Support gapDeg = 0 when type = 'dashboard'
@ -39,7 +34,7 @@ export default defineComponent({
}); });
const circleStyle = computed<CSSProperties>(() => { const circleStyle = computed<CSSProperties>(() => {
const circleSize = props.width || 120; const circleSize = props.width;
return { return {
width: typeof circleSize === 'number' ? `${circleSize}px` : circleSize, width: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
height: typeof circleSize === 'number' ? `${circleSize}px` : circleSize, height: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
@ -47,9 +42,11 @@ export default defineComponent({
}; };
}); });
const circleWidth = computed(() => props.strokeWidth || 6); const circleWidth = computed(
() => props.strokeWidth ?? Math.max(getMinPercent(props.width), 6),
);
const gapPos = computed( const gapPos = computed(
() => props.gapPosition || (props.type === 'dashboard' && 'bottom') || 'top', () => props.gapPosition || (props.type === 'dashboard' && 'bottom') || undefined,
); );
// using className to style stroke color // using className to style stroke color
@ -65,8 +62,8 @@ export default defineComponent({
[`${props.prefixCls}-circle-gradient`]: isGradient.value, [`${props.prefixCls}-circle-gradient`]: isGradient.value,
})); }));
return () => ( return () => {
<div class={wrapperClassName.value} style={circleStyle.value}> const circleContent = (
<VCCircle <VCCircle
percent={percent.value} percent={percent.value}
strokeWidth={circleWidth.value} strokeWidth={circleWidth.value}
@ -78,8 +75,19 @@ export default defineComponent({
gapDegree={gapDeg.value} gapDegree={gapDeg.value}
gapPosition={gapPos.value} gapPosition={gapPos.value}
/> />
);
return (
<div class={wrapperClassName.value} style={circleStyle.value}>
{props.width <= 20 ? (
<Tooltip v-slots={{ title: slots.default }}>{circleContent}</Tooltip>
) : (
<>
{circleContent}
{slots.default?.()} {slots.default?.()}
</>
)}
</div> </div>
); );
};
}, },
}); });

View File

@ -53,7 +53,10 @@ export const sortGradient = (gradients: StringGradients) => {
* "100%": "#ffffff" * "100%": "#ffffff"
* } * }
*/ */
export const handleGradient = (strokeColor: ProgressGradient, directionConfig: Direction) => { export const handleGradient = (
strokeColor: ProgressGradient,
directionConfig?: Direction,
): CSSProperties => {
const { const {
from = presetPrimaryColors.blue, from = presetPrimaryColors.blue,
to = presetPrimaryColors.blue, to = presetPrimaryColors.blue,
@ -70,18 +73,19 @@ export const handleGradient = (strokeColor: ProgressGradient, directionConfig: D
export default defineComponent({ export default defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
name: 'Line', name: 'Line',
inheritAttrs: false,
props: lineProps(), props: lineProps(),
setup(props, { slots }) { setup(props, { slots, attrs }) {
const backgroundProps = computed(() => { const backgroundProps = computed<CSSProperties>(() => {
const { strokeColor, direction } = props; const { strokeColor, direction } = props;
return strokeColor && typeof strokeColor !== 'string' return strokeColor && typeof strokeColor !== 'string'
? handleGradient(strokeColor, direction) ? handleGradient(strokeColor, direction)
: { : {
background: strokeColor, backgroundColor: strokeColor as string,
}; };
}); });
const trailStyle = computed(() => const trailStyle = computed<CSSProperties>(() =>
props.trailColor props.trailColor
? { ? {
backgroundColor: props.trailColor, backgroundColor: props.trailColor,
@ -114,7 +118,7 @@ export default defineComponent({
return () => ( return () => (
<> <>
<div class={`${props.prefixCls}-outer`}> <div {...attrs} class={[`${props.prefixCls}-outer`, attrs.class]}>
<div class={`${props.prefixCls}-inner`} style={trailStyle.value}> <div class={`${props.prefixCls}-inner`} style={trailStyle.value}>
<div class={`${props.prefixCls}-bg`} style={percentStyle.value} /> <div class={`${props.prefixCls}-bg`} style={percentStyle.value} />
{successPercent.value !== undefined ? ( {successPercent.value !== undefined ? (

View File

@ -2,7 +2,7 @@
category: Components category: Components
type: Feedback type: Feedback
title: Progress title: Progress
cover: https://gw.alipayobjects.com/zos/alicdn/xqsDu4ZyR/Progress.svg cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*gK_4S6fDRfgAAAAAAAAAAAAADrJ8AQ/original
--- ---
Display the current progress of an operation flow. Display the current progress of an operation flow.

View File

@ -3,7 +3,7 @@ category: Components
type: 反馈 type: 反馈
title: Progress title: Progress
subtitle: 进度条 subtitle: 进度条
cover: https://gw.alipayobjects.com/zos/alicdn/xqsDu4ZyR/Progress.svg cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*gK_4S6fDRfgAAAAAAAAAAAAADrJ8AQ/original
--- ---
展示操作的当前进度。 展示操作的当前进度。

View File

@ -13,7 +13,6 @@ import devWarning from '../vc-util/devWarning';
import { progressProps, progressStatuses } from './props'; import { progressProps, progressStatuses } from './props';
import type { VueNode } from '../_util/type'; import type { VueNode } from '../_util/type';
import useStyle from './style'; import useStyle from './style';
import classNames from '../_util/classNames';
export default defineComponent({ export default defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
@ -37,18 +36,6 @@ export default defineComponent({
'Progress', 'Progress',
'`successPercent` is deprecated. Please use `success.percent` instead.', '`successPercent` is deprecated. Please use `success.percent` instead.',
); );
const classString = computed(() => {
const { type, showInfo, size } = props;
const pre = prefixCls.value;
return {
[hashId.value]: true,
[pre]: true,
[`${pre}-${(type === 'dashboard' && 'circle') || type}`]: true,
[`${pre}-show-info`]: showInfo,
[`${pre}-${size}`]: size,
[`${pre}-rtl`]: direction.value === 'rtl',
};
});
const percentNumber = computed(() => { const percentNumber = computed(() => {
const { percent = 0 } = props; const { percent = 0 } = props;
@ -61,12 +48,27 @@ export default defineComponent({
const progressStatus = computed(() => { const progressStatus = computed(() => {
const { status } = props; const { status } = props;
if (progressStatuses.indexOf(status) < 0 && percentNumber.value >= 100) { if (!progressStatuses.includes(status) && percentNumber.value >= 100) {
return 'success'; return 'success';
} }
return status || 'normal'; return status || 'normal';
}); });
const classString = computed(() => {
const { type, showInfo, size } = props;
const pre = prefixCls.value;
return {
[pre]: true,
[`${pre}-inline-circle`]: type === 'circle' && props.width! <= 20,
[`${pre}-${(type === 'dashboard' && 'circle') || type}`]: true,
[`${pre}-status-${progressStatus.value}`]: true,
[`${pre}-show-info`]: showInfo,
[`${pre}-${size}`]: size,
[`${pre}-rtl`]: direction.value === 'rtl',
[hashId.value]: true,
};
});
const renderProcessInfo = () => { const renderProcessInfo = () => {
const { showInfo, format, type, percent, title } = props; const { showInfo, format, type, percent, title } = props;
const successPercent = getSuccessPercent(props); const successPercent = getSuccessPercent(props);
@ -126,12 +128,8 @@ export default defineComponent({
); );
} }
const classes = classNames(classString.value, {
[`${prefixCls.value}-status-${progressStatus.value}`]: true,
});
return wrapSSR( return wrapSSR(
<div {...restAttrs} class={[classes, cls]} title={title}> <div role="progressbar" {...restAttrs} class={[classString.value, cls]} title={title}>
{progress} {progress}
</div>, </div>,
); );

View File

@ -1,45 +1,40 @@
import PropTypes from '../_util/vue-types';
import type { VueNode } from '../_util/type'; import type { VueNode } from '../_util/type';
import { tuple } from '../_util/type'; import { functionType, stringType, anyType, objectType } from '../_util/type';
import type { PropType, ExtractPropTypes } from 'vue'; import type { ExtractPropTypes } from 'vue';
export const progressStatuses = tuple('normal', 'exception', 'active', 'success'); export const progressStatuses = ['normal', 'exception', 'active', 'success'] as const;
export type ProgressStatusesType = typeof progressStatuses[number]; export type ProgressStatusesType = (typeof progressStatuses)[number];
const ProgressType = tuple('line', 'circle', 'dashboard'); const ProgressType = ['line', 'circle', 'dashboard'] as const;
export type ProgressType = typeof ProgressType[number]; export type ProgressType = (typeof ProgressType)[number];
const ProgressSize = tuple('default', 'small'); const ProgressSize = ['default', 'small'] as const;
export type ProgressSize = typeof ProgressSize[number]; export type ProgressSize = (typeof ProgressSize)[number];
export type StringGradients = { [percentage: string]: string }; export type StringGradients = { [percentage: string]: string };
type FromToGradients = { from: string; to: string }; type FromToGradients = { from: string; to: string };
export type ProgressGradient = { direction?: string } & (StringGradients | FromToGradients); export type ProgressGradient = { direction?: string } & (StringGradients | FromToGradients);
export interface SuccessProps { export interface SuccessProps {
percent?: number; percent?: number;
/** @deprecated Use `percent` instead */
progress?: number;
strokeColor?: string; strokeColor?: string;
} }
export const progressProps = () => ({ export const progressProps = () => ({
prefixCls: String, prefixCls: String,
type: PropTypes.oneOf(ProgressType), type: stringType<ProgressType>(),
percent: Number, percent: Number,
format: { type: Function as PropType<(percent?: number, successPercent?: number) => VueNode> }, format: functionType<(percent?: number, successPercent?: number) => VueNode>(),
status: PropTypes.oneOf(progressStatuses), status: stringType<ProgressStatusesType>(),
showInfo: { type: Boolean, default: undefined }, showInfo: { type: Boolean, default: undefined },
strokeWidth: Number, strokeWidth: Number,
strokeLinecap: String as PropType<'butt' | 'square' | 'round'>, strokeLinecap: stringType<'butt' | 'square' | 'round'>(),
strokeColor: { strokeColor: anyType<string | ProgressGradient>(),
type: [String, Object] as PropType<string | ProgressGradient>,
default: undefined as string | ProgressGradient,
},
trailColor: String, trailColor: String,
width: Number, width: Number,
success: { success: objectType<SuccessProps>(),
type: Object as PropType<SuccessProps>,
default: (): SuccessProps => ({}),
},
gapDegree: Number, gapDegree: Number,
gapPosition: String as PropType<'top' | 'bottom' | 'left' | 'right'>, gapPosition: stringType<'top' | 'bottom' | 'left' | 'right'>(),
size: PropTypes.oneOf(ProgressSize), size: stringType<ProgressSize>(),
steps: Number, steps: Number,
/** @deprecated Use `success` instead */ /** @deprecated Use `success` instead */
successPercent: Number, successPercent: Number,

View File

@ -1,4 +1,7 @@
import { presetPrimaryColors } from '@ant-design/colors';
import devWarning from '../vc-util/devWarning'; import devWarning from '../vc-util/devWarning';
import type { CircleProps } from './Circle';
import type { ProgressProps } from './props';
export function validProgress(progress: number | undefined) { export function validProgress(progress: number | undefined) {
if (!progress || progress < 0) { if (!progress || progress < 0) {
@ -10,16 +13,7 @@ export function validProgress(progress: number | undefined) {
return progress; return progress;
} }
export function getSuccessPercent({ export function getSuccessPercent({ success, successPercent }: ProgressProps) {
success,
successPercent,
}: {
success?: {
progress?: number;
percent?: number;
};
successPercent?: number;
}) {
let percent = successPercent; let percent = successPercent;
/** @deprecated Use `percent` instead */ /** @deprecated Use `percent` instead */
if (success && 'progress' in success) { if (success && 'progress' in success) {
@ -35,3 +29,16 @@ export function getSuccessPercent({
} }
return percent; return percent;
} }
export function getPercentage({ percent, success, successPercent }: ProgressProps) {
const realSuccessPercent = validProgress(getSuccessPercent({ success, successPercent }));
return [realSuccessPercent, validProgress(validProgress(percent) - realSuccessPercent)];
}
export function getStrokeColor({
success = {},
strokeColor,
}: Partial<CircleProps>): (string | Record<string, string>)[] {
const { strokeColor: successColor } = success;
return [successColor || presetPrimaryColors.green, strokeColor || null!];
}