refactor: progress #6234

This commit is contained in:
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 };
}
export function functionType<T = () => {}>(defaultVal?: any) {
return { type: Function as PropType<T>, default: defaultVal as T };
}
export function anyType<T = any>() {
return { validator: () => true } as unknown as { type: PropType<T> };
}

View File

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

View File

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

View File

@ -2,7 +2,7 @@
category: Components
type: Feedback
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.

View File

@ -3,7 +3,7 @@ category: Components
type: 反馈
title: Progress
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 type { VueNode } from '../_util/type';
import useStyle from './style';
import classNames from '../_util/classNames';
export default defineComponent({
compatConfig: { MODE: 3 },
@ -37,18 +36,6 @@ export default defineComponent({
'Progress',
'`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 { percent = 0 } = props;
@ -61,12 +48,27 @@ export default defineComponent({
const progressStatus = computed(() => {
const { status } = props;
if (progressStatuses.indexOf(status) < 0 && percentNumber.value >= 100) {
if (!progressStatuses.includes(status) && percentNumber.value >= 100) {
return 'success';
}
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 { showInfo, format, type, percent, title } = 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(
<div {...restAttrs} class={[classes, cls]} title={title}>
<div role="progressbar" {...restAttrs} class={[classString.value, cls]} title={title}>
{progress}
</div>,
);

View File

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

View File

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