refactor: progress #6234
parent
2c1afa5e72
commit
a40816880a
|
@ -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> };
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 ? (
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
展示操作的当前进度。
|
展示操作的当前进度。
|
||||||
|
|
|
@ -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>,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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!];
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue