refactor: steps
parent
899757a054
commit
740ba04c02
|
@ -3,3 +3,5 @@ timeline: 新增 label
|
|||
tree、tree-slelct: 新增虚拟滚动、title 逻辑变动
|
||||
|
||||
date 相关组件: dayjs, UI 变动
|
||||
|
||||
steps: add responsive、percent
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
import type { App, ExtractPropTypes, Plugin } from 'vue';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
|
||||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
||||
import { getOptionProps, getComponent, getSlot } from '../_util/props-util';
|
||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||
import VcSteps from '../vc-steps';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import { tuple } from '../_util/type';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
import useBreakpoint from '../_util/hooks/useBreakpoint';
|
||||
import classNames from '../_util/classNames';
|
||||
import Progress from '../progress';
|
||||
import omit from '../_util/omit';
|
||||
|
||||
const stepsProps = {
|
||||
export const stepsProps = () => ({
|
||||
prefixCls: PropTypes.string,
|
||||
iconPrefix: PropTypes.string,
|
||||
current: PropTypes.number,
|
||||
initial: PropTypes.number,
|
||||
percent: PropTypes.number,
|
||||
responsive: PropTypes.looseBool,
|
||||
labelPlacement: PropTypes.oneOf(tuple('horizontal', 'vertical')).def('horizontal'),
|
||||
status: PropTypes.oneOf(tuple('wait', 'process', 'finish', 'error')),
|
||||
size: PropTypes.oneOf(tuple('default', 'small')),
|
||||
|
@ -22,52 +28,98 @@ const stepsProps = {
|
|||
type: PropTypes.oneOf(tuple('default', 'navigation')),
|
||||
onChange: PropTypes.func,
|
||||
'onUpdate:current': PropTypes.func,
|
||||
};
|
||||
});
|
||||
|
||||
export type StepsProps = Partial<ExtractPropTypes<typeof stepsProps>>;
|
||||
export const stepProps = () => ({
|
||||
description: PropTypes.any,
|
||||
icon: PropTypes.any,
|
||||
status: PropTypes.oneOf(tuple('wait', 'process', 'finish', 'error')),
|
||||
disabled: PropTypes.looseBool,
|
||||
title: PropTypes.any,
|
||||
subTitle: PropTypes.any,
|
||||
onClick: PropTypes.func,
|
||||
});
|
||||
|
||||
export type StepsProps = Partial<ExtractPropTypes<ReturnType<typeof stepsProps>>>;
|
||||
|
||||
export type StepProps = Partial<ExtractPropTypes<ReturnType<typeof stepProps>>>;
|
||||
|
||||
const Steps = defineComponent({
|
||||
name: 'ASteps',
|
||||
inheritAttrs: false,
|
||||
props: initDefaultProps(stepsProps, {
|
||||
props: initDefaultProps(stepsProps(), {
|
||||
current: 0,
|
||||
responsive: true,
|
||||
}),
|
||||
slots: ['progressDot'],
|
||||
emits: ['update:current', 'change'],
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
setup(props, { attrs, slots, emit }) {
|
||||
const { prefixCls, direction: rtlDirection, configProvider } = useConfigInject('steps', props);
|
||||
const screens = useBreakpoint();
|
||||
const direction = computed(() =>
|
||||
props.responsive && screens.value.xs ? 'vertical' : props.direction,
|
||||
);
|
||||
const iconPrefix = computed(() => configProvider.getPrefixCls('', props.iconPrefix));
|
||||
const handleChange = (current: number) => {
|
||||
emit('update:current', current);
|
||||
emit('change', current);
|
||||
};
|
||||
const stepIconRender = ({
|
||||
node,
|
||||
status,
|
||||
}: {
|
||||
node: any;
|
||||
index: number;
|
||||
status: string;
|
||||
title: any;
|
||||
description: any;
|
||||
}) => {
|
||||
if (status === 'process' && props.percent !== undefined) {
|
||||
// currently it's hard-coded, since we can't easily read the actually width of icon
|
||||
const progressWidth = props.size === 'small' ? 32 : 40;
|
||||
const iconWithProgress = (
|
||||
<div class={`${prefixCls}-progress-icon`}>
|
||||
<Progress
|
||||
type="circle"
|
||||
percent={props.percent}
|
||||
width={progressWidth}
|
||||
strokeWidth={4}
|
||||
format={() => null}
|
||||
/>
|
||||
{node}
|
||||
</div>
|
||||
);
|
||||
return iconWithProgress;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
return () => {
|
||||
const stepsClassName = classNames(
|
||||
{
|
||||
[`${prefixCls.value}-rtl`]: rtlDirection.value === 'rtl',
|
||||
[`${prefixCls.value}-with-progress`]: props.percent !== undefined,
|
||||
},
|
||||
attrs.class,
|
||||
);
|
||||
const icons = {
|
||||
finish: <CheckOutlined class={`${prefixCls}-finish-icon`} />,
|
||||
error: <CloseOutlined class={`${prefixCls}-error-icon`} />,
|
||||
};
|
||||
return (
|
||||
<VcSteps
|
||||
icons={icons}
|
||||
{...omit(props, ['percent', 'responsive'])}
|
||||
direction={direction.value}
|
||||
prefixCls={prefixCls.value}
|
||||
iconPrefix={iconPrefix.value}
|
||||
class={stepsClassName}
|
||||
onChange={handleChange}
|
||||
v-slots={{ ...slots, stepIcon: stepIconRender }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
},
|
||||
Step: { ...VcSteps.Step, name: 'AStep' },
|
||||
methods: {
|
||||
handleChange(current: number) {
|
||||
this.$emit('update:current', current);
|
||||
this.$emit('change', current);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const props: StepsProps = { ...getOptionProps(this), ...this.$attrs };
|
||||
const { prefixCls: customizePrefixCls, iconPrefix: customizeIconPrefixCls } = props;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('steps', customizePrefixCls);
|
||||
const iconPrefix = getPrefixCls('', customizeIconPrefixCls);
|
||||
const progressDot = getComponent(this, 'progressDot', this, false);
|
||||
|
||||
const icons = {
|
||||
finish: <CheckOutlined class={`${prefixCls}-finish-icon`} />,
|
||||
error: <CloseOutlined class={`${prefixCls}-error-icon`} />,
|
||||
};
|
||||
const stepsProps = {
|
||||
icons,
|
||||
iconPrefix,
|
||||
prefixCls,
|
||||
progressDot,
|
||||
...props,
|
||||
canClick: !!(this.onChange || this['onUpdate:current']),
|
||||
onChange: this.handleChange,
|
||||
};
|
||||
return <VcSteps {...stepsProps}>{getSlot(this)}</VcSteps>;
|
||||
},
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
.@{steps-prefix-cls}-flex-not-supported {
|
||||
&.@{steps-prefix-cls}-horizontal.@{steps-prefix-cls}-label-horizontal {
|
||||
.@{steps-prefix-cls}-item {
|
||||
margin-left: -16px;
|
||||
padding-left: 16px;
|
||||
background: @steps-background;
|
||||
}
|
||||
|
||||
&.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item {
|
||||
margin-left: -12px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{steps-prefix-cls}-dot {
|
||||
.@{steps-prefix-cls}-item {
|
||||
&:last-child {
|
||||
overflow: hidden;
|
||||
|
||||
.@{steps-prefix-cls}-icon-dot::after {
|
||||
right: -200px;
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-icon-dot::before,
|
||||
.@{steps-prefix-cls}-icon-dot::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -10px;
|
||||
width: 10px;
|
||||
height: 8px;
|
||||
background: @steps-background;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-icon-dot::after {
|
||||
right: -10px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-item-wait
|
||||
.@{steps-prefix-cls}-item-icon
|
||||
> .@{steps-prefix-cls}-icon
|
||||
.@{steps-prefix-cls}-icon-dot {
|
||||
background: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
.@{steps-prefix-cls}-item-custom {
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
> .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-icon {
|
||||
height: auto;
|
||||
background: none;
|
||||
border: 0;
|
||||
> .@{steps-prefix-cls}-icon {
|
||||
top: 0;
|
||||
top: @steps-icon-custom-top;
|
||||
left: 0.5px;
|
||||
width: @steps-icon-size;
|
||||
height: @steps-icon-size;
|
||||
font-size: 24px;
|
||||
line-height: @steps-icon-size;
|
||||
width: @steps-icon-custom-size;
|
||||
height: @steps-icon-custom-size;
|
||||
font-size: @steps-icon-custom-font-size;
|
||||
line-height: @steps-icon-custom-size;
|
||||
}
|
||||
}
|
||||
&.@{steps-prefix-cls}-item-process {
|
||||
|
@ -25,6 +25,7 @@
|
|||
.@{steps-prefix-cls}-item-custom {
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
width: auto;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
@process-icon-color: @primary-color;
|
||||
@process-title-color: @heading-color;
|
||||
@process-description-color: @text-color;
|
||||
@process-tail-color: @border-color-split;
|
||||
@process-icon-text-color: @text-color-inverse;
|
||||
@wait-icon-color: @disabled-color;
|
||||
@wait-title-color: @text-color-secondary;
|
||||
|
@ -21,19 +20,13 @@
|
|||
@error-tail-color: @wait-tail-color;
|
||||
@steps-nav-active-color: @primary-color;
|
||||
|
||||
@steps-icon-size: 32px;
|
||||
@steps-small-icon-size: 24px;
|
||||
@steps-dot-size: 8px;
|
||||
@steps-current-dot-size: 10px;
|
||||
@steps-desciption-max-width: 140px;
|
||||
@steps-nav-content-max-width: auto;
|
||||
|
||||
.@{steps-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
display: flex;
|
||||
width: 100%;
|
||||
font-size: 0;
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-item {
|
||||
|
@ -65,8 +58,8 @@
|
|||
&-icon {
|
||||
width: @steps-icon-size;
|
||||
height: @steps-icon-size;
|
||||
margin-right: 8px;
|
||||
font-size: @font-size-lg;
|
||||
margin: @steps-icon-margin;
|
||||
font-size: @steps-icon-font-size;
|
||||
font-family: @font-family;
|
||||
line-height: @steps-icon-size;
|
||||
text-align: center;
|
||||
|
@ -74,9 +67,9 @@
|
|||
border-radius: @steps-icon-size;
|
||||
transition: background-color 0.3s, border-color 0.3s;
|
||||
|
||||
> .@{steps-prefix-cls}-icon {
|
||||
.@{steps-prefix-cls}-icon {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
top: @steps-icon-top;
|
||||
color: @primary-color;
|
||||
line-height: 1;
|
||||
}
|
||||
|
@ -87,6 +80,7 @@
|
|||
left: 0;
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
|
||||
&::after {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
|
@ -103,10 +97,11 @@
|
|||
padding-right: 16px;
|
||||
color: @text-color;
|
||||
font-size: @font-size-lg;
|
||||
line-height: @steps-icon-size;
|
||||
line-height: @steps-title-line-height;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: (@steps-icon-size / 2);
|
||||
top: (@steps-title-line-height / 2);
|
||||
left: 100%;
|
||||
display: block;
|
||||
width: 9999px;
|
||||
|
@ -128,13 +123,13 @@
|
|||
}
|
||||
.step-item-status(wait);
|
||||
.step-item-status(process);
|
||||
&-process &-icon {
|
||||
&-process > &-container > &-icon {
|
||||
background: @process-icon-color;
|
||||
> .@{steps-prefix-cls}-icon {
|
||||
.@{steps-prefix-cls}-icon {
|
||||
color: @process-icon-text-color;
|
||||
}
|
||||
}
|
||||
&-process &-title {
|
||||
&-process > &-container > &-title {
|
||||
font-weight: 500;
|
||||
}
|
||||
.step-item-status(finish);
|
||||
|
@ -143,6 +138,10 @@
|
|||
&.@{steps-prefix-cls}-next-error .@{steps-prefix-cls}-item-title::after {
|
||||
background: @error-icon-color;
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== Clickable =====================
|
||||
|
@ -153,6 +152,7 @@
|
|||
|
||||
.@{steps-prefix-cls}-item {
|
||||
&-title,
|
||||
&-subtitle,
|
||||
&-description,
|
||||
&-icon .@{steps-prefix-cls}-icon {
|
||||
transition: color 0.3s;
|
||||
|
@ -188,10 +188,11 @@
|
|||
|
||||
.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical) {
|
||||
.@{steps-prefix-cls}-item {
|
||||
margin-right: 16px;
|
||||
padding-left: 16px;
|
||||
white-space: nowrap;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
&:last-child .@{steps-prefix-cls}-item-title {
|
||||
padding-right: 0;
|
||||
|
@ -200,7 +201,7 @@
|
|||
display: none;
|
||||
}
|
||||
&-description {
|
||||
max-width: @steps-desciption-max-width;
|
||||
max-width: @steps-description-max-width;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
@ -235,10 +236,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
@import 'custom-icon';
|
||||
@import 'small';
|
||||
@import 'vertical';
|
||||
@import 'label-placement';
|
||||
@import 'progress-dot';
|
||||
@import 'nav';
|
||||
@import 'compatibility';
|
||||
@import './custom-icon';
|
||||
@import './small';
|
||||
@import './vertical';
|
||||
@import './label-placement';
|
||||
@import './progress-dot';
|
||||
@import './nav';
|
||||
@import './rtl';
|
||||
@import './progress.less';
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
import '../../style/index.less';
|
||||
import './index.less';
|
|
@ -0,0 +1,6 @@
|
|||
import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
// deps-lint-skip: grid
|
||||
import '../../progress/style';
|
|
@ -17,6 +17,7 @@
|
|||
}
|
||||
&-title {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
left: 50%;
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 3px;
|
||||
height: 2px;
|
||||
background-color: @steps-nav-active-color;
|
||||
transition: width 0.3s, left 0.3s;
|
||||
transition-timing-function: ease-out;
|
||||
|
@ -90,35 +90,33 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs) {
|
||||
.@{steps-prefix-cls}-navigation {
|
||||
> .@{steps-prefix-cls}-item {
|
||||
margin-right: 0 !important;
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
&.@{steps-prefix-cls}-item-active::before {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: unset;
|
||||
display: block;
|
||||
width: 3px;
|
||||
height: calc(100% - 24px);
|
||||
}
|
||||
&::after {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
left: 50%;
|
||||
display: block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
> .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {
|
||||
visibility: hidden;
|
||||
}
|
||||
.@{steps-prefix-cls}-navigation.@{steps-prefix-cls}-vertical {
|
||||
> .@{steps-prefix-cls}-item {
|
||||
margin-right: 0 !important;
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
&.@{steps-prefix-cls}-item-active::before {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: unset;
|
||||
display: block;
|
||||
width: 3px;
|
||||
height: calc(100% - 24px);
|
||||
}
|
||||
&::after {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
left: 50%;
|
||||
display: block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
> .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
line-height: @line-height-base;
|
||||
}
|
||||
&-tail {
|
||||
top: 2px;
|
||||
top: @steps-dot-top;
|
||||
width: 100%;
|
||||
margin: 0 0 0 (@steps-desciption-max-width / 2);
|
||||
margin: 0 0 0 (@steps-description-max-width / 2);
|
||||
padding: 0;
|
||||
|
||||
&::after {
|
||||
width: ~'calc(100% - 20px)';
|
||||
height: 3px;
|
||||
|
@ -26,6 +27,7 @@
|
|||
line-height: @steps-dot-size;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
|
||||
.@{steps-prefix-cls}-icon-dot {
|
||||
position: relative;
|
||||
float: left;
|
||||
|
@ -46,14 +48,19 @@
|
|||
}
|
||||
}
|
||||
&-content {
|
||||
width: @steps-desciption-max-width;
|
||||
width: @steps-description-max-width;
|
||||
}
|
||||
&-process .@{steps-prefix-cls}-item-icon {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
width: @steps-current-dot-size;
|
||||
height: @steps-current-dot-size;
|
||||
line-height: @steps-current-dot-size;
|
||||
.@{steps-prefix-cls}-icon-dot {
|
||||
top: -1px;
|
||||
background: none;
|
||||
}
|
||||
&-process .@{steps-prefix-cls}-icon {
|
||||
&:first-child .@{steps-prefix-cls}-icon-dot {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +70,7 @@
|
|||
.@{steps-prefix-cls}-item-icon {
|
||||
margin-top: 8px;
|
||||
margin-left: 0;
|
||||
background: none;
|
||||
}
|
||||
// https://github.com/ant-design/ant-design/issues/18354
|
||||
.@{steps-prefix-cls}-item > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {
|
||||
|
@ -74,7 +82,13 @@
|
|||
.@{steps-prefix-cls}-item:first-child .@{steps-prefix-cls}-icon-dot {
|
||||
left: 0;
|
||||
}
|
||||
.@{steps-prefix-cls}-item-process .@{steps-prefix-cls}-icon-dot {
|
||||
.@{steps-prefix-cls}-item-content {
|
||||
width: inherit;
|
||||
}
|
||||
.@{steps-prefix-cls}-item-process
|
||||
.@{steps-prefix-cls}-item-container
|
||||
.@{steps-prefix-cls}-item-icon
|
||||
.@{steps-prefix-cls}-icon-dot {
|
||||
left: -2px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
@progress-prefix-cls: ~'@{ant-prefix}-progress';
|
||||
|
||||
.@{steps-prefix-cls}-with-progress {
|
||||
.@{steps-prefix-cls}-item {
|
||||
padding-top: 4px;
|
||||
|
||||
.@{steps-prefix-cls}-item-tail {
|
||||
top: 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{steps-prefix-cls}-horizontal .@{steps-prefix-cls}-item:first-child {
|
||||
padding-bottom: 4px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
position: relative;
|
||||
|
||||
.@{progress-prefix-cls} {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
bottom: -5px;
|
||||
left: -5px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
.@{steps-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-item {
|
||||
&-icon {
|
||||
.@{steps-prefix-cls}.@{steps-prefix-cls}-rtl & {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-tail {
|
||||
.@{steps-prefix-cls}-rtl & {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
.@{steps-prefix-cls}-rtl & {
|
||||
padding-right: 0;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
.@{steps-prefix-cls}-rtl & {
|
||||
right: 100%;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical) {
|
||||
.@{steps-prefix-cls}-item {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-right: 16px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
&:last-child .@{steps-prefix-cls}-item-title {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// custom-icon
|
||||
.@{steps-prefix-cls}-item-custom {
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
> .@{steps-prefix-cls}-icon {
|
||||
.@{steps-prefix-cls}-rtl & {
|
||||
right: 0.5px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nav
|
||||
.@{steps-prefix-cls}-navigation {
|
||||
&.@{steps-prefix-cls}-small {
|
||||
.@{steps-prefix-cls}-item {
|
||||
&-container {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
margin-right: -12px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-item {
|
||||
&-container {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
margin-right: -16px;
|
||||
margin-left: 0;
|
||||
text-align: right;
|
||||
}
|
||||
.@{steps-prefix-cls}-item-title {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: 100%;
|
||||
left: auto;
|
||||
margin-right: -2px;
|
||||
margin-left: 0;
|
||||
transform: rotate(225deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// small
|
||||
.@{steps-prefix-cls}-small {
|
||||
&.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)
|
||||
.@{steps-prefix-cls}-item {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-right: 12px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-item-title {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-right: 0;
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vertical
|
||||
.@{steps-prefix-cls}-vertical {
|
||||
> .@{steps-prefix-cls}-item {
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-left: @steps-vertical-icon-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .@{steps-prefix-cls}-item
|
||||
> .@{steps-prefix-cls}-item-container
|
||||
> .@{steps-prefix-cls}-item-tail {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: @steps-vertical-tail-width;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item-container {
|
||||
.@{steps-prefix-cls}-item-tail {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: @steps-vertical-tail-width-sm;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// label
|
||||
.@{steps-prefix-cls}-label-vertical {
|
||||
.@{steps-prefix-cls}-item {
|
||||
&-title {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// progress-dot
|
||||
.@{steps-prefix-cls}-dot,
|
||||
.@{steps-prefix-cls}-dot.@{steps-prefix-cls}-small {
|
||||
.@{steps-prefix-cls}-item {
|
||||
&-tail {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
margin: 0 (@steps-description-max-width / 2) 0 0;
|
||||
}
|
||||
|
||||
&::after {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
margin-right: 12px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:first-child .@{steps-prefix-cls}-icon-dot {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: 2px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
&-icon {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
margin-right: 67px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-icon-dot {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
float: right;
|
||||
}
|
||||
/* expand hover area */
|
||||
&::after {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: -26px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-vertical.@{steps-prefix-cls}-dot {
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
margin-right: 0;
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
// https://github.com/ant-design/ant-design/issues/18354
|
||||
.@{steps-prefix-cls}-item > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: -9px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
.@{steps-prefix-cls}-item:first-child .@{steps-prefix-cls}-icon-dot {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
.@{steps-prefix-cls}-item-process .@{steps-prefix-cls}-icon-dot {
|
||||
.@{steps-prefix-cls}-rtl& {
|
||||
right: -2px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RTL Steps with progress
|
||||
.@{steps-prefix-cls}-rtl.@{steps-prefix-cls}-with-progress.@{steps-prefix-cls}-horizontal.@{steps-prefix-cls}-label-horizontal {
|
||||
.@{steps-prefix-cls}-item:first-child.@{steps-prefix-cls}-item-active {
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
.@{steps-prefix-cls}-small {
|
||||
&.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)
|
||||
.@{steps-prefix-cls}-item {
|
||||
margin-right: 12px;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
padding-left: 12px;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
width: @steps-small-icon-size;
|
||||
height: @steps-small-icon-size;
|
||||
margin: @steps-small-icon-margin;
|
||||
font-size: @font-size-sm;
|
||||
line-height: @steps-small-icon-size;
|
||||
text-align: center;
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
.steps-vertical() {
|
||||
display: block;
|
||||
.@{steps-prefix-cls}-item {
|
||||
.@{steps-prefix-cls}-vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> .@{steps-prefix-cls}-item {
|
||||
display: block;
|
||||
flex: 1 0 auto;
|
||||
padding-left: 0;
|
||||
overflow: visible;
|
||||
&-icon {
|
||||
|
||||
.@{steps-prefix-cls}-item-icon {
|
||||
float: left;
|
||||
margin-right: 16px;
|
||||
margin-right: @steps-vertical-icon-width;
|
||||
}
|
||||
&-content {
|
||||
|
||||
.@{steps-prefix-cls}-item-content {
|
||||
display: block;
|
||||
min-height: 48px;
|
||||
overflow: hidden;
|
||||
}
|
||||
&-title {
|
||||
|
||||
.@{steps-prefix-cls}-item-title {
|
||||
line-height: @steps-icon-size;
|
||||
}
|
||||
&-description {
|
||||
|
||||
.@{steps-prefix-cls}-item-description {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +33,11 @@
|
|||
> .@{steps-prefix-cls}-item-tail {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 16px;
|
||||
left: @steps-vertical-tail-width;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
padding: @steps-icon-size + 6px 0 6px;
|
||||
|
||||
&::after {
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
|
@ -54,7 +63,7 @@
|
|||
.@{steps-prefix-cls}-item-tail {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 12px;
|
||||
left: @steps-vertical-tail-width-sm;
|
||||
padding: @steps-small-icon-size + 6px 0 6px;
|
||||
}
|
||||
.@{steps-prefix-cls}-item-title {
|
||||
|
@ -62,13 +71,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{steps-prefix-cls}-vertical {
|
||||
.steps-vertical();
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs) {
|
||||
.@{steps-prefix-cls}-horizontal.@{steps-prefix-cls}-label-horizontal {
|
||||
.steps-vertical();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -887,8 +887,28 @@
|
|||
@image-preview-operation-disabled-color: fade(@image-preview-operation-color, 45%);
|
||||
|
||||
// Steps
|
||||
// ---
|
||||
@process-tail-color: @border-color-split;
|
||||
@steps-nav-arrow-color: fade(@black, 25%);
|
||||
@steps-background: @component-background;
|
||||
@steps-icon-size: 32px;
|
||||
@steps-icon-custom-size: @steps-icon-size;
|
||||
@steps-icon-custom-top: 0px;
|
||||
@steps-icon-custom-font-size: 24px;
|
||||
@steps-icon-top: -0.5px;
|
||||
@steps-icon-font-size: @font-size-lg;
|
||||
@steps-icon-margin: 0 8px 0 0;
|
||||
@steps-title-line-height: @height-base;
|
||||
@steps-small-icon-size: 24px;
|
||||
@steps-small-icon-margin: 0 8px 0 0;
|
||||
@steps-dot-size: 8px;
|
||||
@steps-dot-top: 2px;
|
||||
@steps-current-dot-size: 10px;
|
||||
@steps-description-max-width: 140px;
|
||||
@steps-nav-content-max-width: auto;
|
||||
@steps-vertical-icon-width: 16px;
|
||||
@steps-vertical-tail-width: 16px;
|
||||
@steps-vertical-tail-width-sm: 12px;
|
||||
|
||||
// Notification
|
||||
// ---
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
||||
import { getOptionProps, getComponent } from '../_util/props-util';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
function isString(str) {
|
||||
return typeof str === 'string';
|
||||
}
|
||||
function noop() {}
|
||||
export default defineComponent({
|
||||
name: 'Step',
|
||||
mixins: [BaseMixin],
|
||||
props: {
|
||||
prefixCls: PropTypes.string,
|
||||
wrapperStyle: PropTypes.object,
|
||||
itemWidth: PropTypes.string,
|
||||
active: PropTypes.looseBool,
|
||||
disabled: PropTypes.looseBool,
|
||||
status: PropTypes.string,
|
||||
iconPrefix: PropTypes.string,
|
||||
icon: PropTypes.any,
|
||||
adjustMarginRight: PropTypes.string,
|
||||
stepNumber: PropTypes.string,
|
||||
stepIndex: PropTypes.number,
|
||||
description: PropTypes.any,
|
||||
title: PropTypes.any,
|
||||
subTitle: PropTypes.any,
|
||||
progressDot: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
|
||||
tailContent: PropTypes.any,
|
||||
icons: PropTypes.shape({
|
||||
finish: PropTypes.any,
|
||||
error: PropTypes.any,
|
||||
}).loose,
|
||||
onClick: PropTypes.func,
|
||||
onStepClick: PropTypes.func,
|
||||
},
|
||||
methods: {
|
||||
onItemClick(...args) {
|
||||
this.__emit('click', ...args);
|
||||
this.__emit('stepClick', this.stepIndex);
|
||||
},
|
||||
renderIconNode() {
|
||||
const { prefixCls, stepNumber, status, iconPrefix, icons, progressDot } =
|
||||
getOptionProps(this);
|
||||
const icon = getComponent(this, 'icon');
|
||||
const title = getComponent(this, 'title');
|
||||
const description = getComponent(this, 'description');
|
||||
let iconNode;
|
||||
const iconClassName = {
|
||||
[`${prefixCls}-icon`]: true,
|
||||
[`${iconPrefix}icon`]: true,
|
||||
[`${iconPrefix}icon-${icon}`]: icon && isString(icon),
|
||||
[`${iconPrefix}icon-check`]: !icon && status === 'finish' && icons && !icons.finish,
|
||||
[`${iconPrefix}icon-close`]: !icon && status === 'error' && icons && !icons.error,
|
||||
};
|
||||
const iconDot = <span class={`${prefixCls}-icon-dot`} />;
|
||||
// `progressDot` enjoy the highest priority
|
||||
if (progressDot) {
|
||||
if (typeof progressDot === 'function') {
|
||||
iconNode = (
|
||||
<span class={`${prefixCls}-icon`}>
|
||||
{progressDot({ index: stepNumber - 1, status, title, description, prefixCls })}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{iconDot}</span>;
|
||||
}
|
||||
} else if (icon && !isString(icon)) {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{icon}</span>;
|
||||
} else if (icons && icons.finish && status === 'finish') {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{icons.finish}</span>;
|
||||
} else if (icons && icons.error && status === 'error') {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{icons.error}</span>;
|
||||
} else if (icon || status === 'finish' || status === 'error') {
|
||||
iconNode = <span class={iconClassName} />;
|
||||
} else {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{stepNumber}</span>;
|
||||
}
|
||||
return iconNode;
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const {
|
||||
prefixCls,
|
||||
itemWidth,
|
||||
active,
|
||||
status = 'wait',
|
||||
tailContent,
|
||||
adjustMarginRight,
|
||||
disabled,
|
||||
onClick,
|
||||
onStepClick,
|
||||
} = getOptionProps(this);
|
||||
|
||||
const title = getComponent(this, 'title');
|
||||
const subTitle = getComponent(this, 'subTitle');
|
||||
const description = getComponent(this, 'description');
|
||||
|
||||
const classString = {
|
||||
[`${prefixCls}-item`]: true,
|
||||
[`${prefixCls}-item-${status}`]: true,
|
||||
[`${prefixCls}-item-custom`]: getComponent(this, 'icon'),
|
||||
[`${prefixCls}-item-active`]: active,
|
||||
[`${prefixCls}-item-disabled`]: disabled === true,
|
||||
};
|
||||
const stepProps = {
|
||||
class: classString,
|
||||
};
|
||||
const stepItemStyle = {};
|
||||
if (itemWidth) {
|
||||
stepItemStyle.width = itemWidth;
|
||||
}
|
||||
if (adjustMarginRight) {
|
||||
stepItemStyle.marginRight = adjustMarginRight;
|
||||
}
|
||||
|
||||
const accessibilityProps = {
|
||||
onClick: onClick || noop,
|
||||
};
|
||||
|
||||
if (onStepClick && !disabled) {
|
||||
accessibilityProps.role = 'button';
|
||||
accessibilityProps.tabindex = 0;
|
||||
accessibilityProps.onClick = this.onItemClick;
|
||||
}
|
||||
return (
|
||||
<div {...stepProps} style={stepItemStyle}>
|
||||
<div {...accessibilityProps} class={`${prefixCls}-item-container`}>
|
||||
<div class={`${prefixCls}-item-tail`}>{tailContent}</div>
|
||||
<div class={`${prefixCls}-item-icon`}>{this.renderIconNode()}</div>
|
||||
<div class={`${prefixCls}-item-content`}>
|
||||
<div class={`${prefixCls}-item-title`}>
|
||||
{title}
|
||||
{subTitle && (
|
||||
<div title={subTitle} class={`${prefixCls}-item-subtitle`}>
|
||||
{subTitle}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{description && <div class={`${prefixCls}-item-description`}>{description}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,177 @@
|
|||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import type { EventHandler } from '../_util/EventInterface';
|
||||
|
||||
function isString(str: any): str is string {
|
||||
return typeof str === 'string';
|
||||
}
|
||||
function noop() {}
|
||||
export default defineComponent({
|
||||
name: 'Step',
|
||||
props: {
|
||||
prefixCls: PropTypes.string,
|
||||
wrapperStyle: PropTypes.style,
|
||||
itemWidth: PropTypes.string,
|
||||
active: PropTypes.looseBool,
|
||||
disabled: PropTypes.looseBool,
|
||||
status: PropTypes.string,
|
||||
iconPrefix: PropTypes.string,
|
||||
icon: PropTypes.any,
|
||||
adjustMarginRight: PropTypes.string,
|
||||
stepNumber: PropTypes.number,
|
||||
stepIndex: PropTypes.number,
|
||||
description: PropTypes.any,
|
||||
title: PropTypes.any,
|
||||
subTitle: PropTypes.any,
|
||||
progressDot: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
|
||||
tailContent: PropTypes.any,
|
||||
icons: PropTypes.shape({
|
||||
finish: PropTypes.any,
|
||||
error: PropTypes.any,
|
||||
}).loose,
|
||||
onClick: PropTypes.func,
|
||||
onStepClick: PropTypes.func,
|
||||
stepIcon: PropTypes.func,
|
||||
},
|
||||
slots: ['title', 'subTitle', 'description', 'tailContent', 'stepIcon', 'progressDot'],
|
||||
emits: ['click', 'stepClick'],
|
||||
setup(props, { slots, emit }) {
|
||||
const onItemClick: EventHandler = e => {
|
||||
emit('click', e);
|
||||
emit('stepClick', props.stepIndex);
|
||||
};
|
||||
|
||||
const renderIconNode = ({ icon, title, description }) => {
|
||||
const {
|
||||
prefixCls,
|
||||
stepNumber,
|
||||
status,
|
||||
iconPrefix,
|
||||
icons,
|
||||
progressDot = slots.progressDot,
|
||||
stepIcon = slots.stepIcon,
|
||||
} = props;
|
||||
|
||||
let iconNode: any;
|
||||
const iconClassName = {
|
||||
[`${prefixCls}-icon`]: true,
|
||||
[`${iconPrefix}icon`]: true,
|
||||
[`${iconPrefix}icon-${icon}`]: icon && isString(icon),
|
||||
[`${iconPrefix}icon-check`]: !icon && status === 'finish' && icons && !icons.finish,
|
||||
[`${iconPrefix}icon-close`]: !icon && status === 'error' && icons && !icons.error,
|
||||
};
|
||||
const iconDot = <span class={`${prefixCls}-icon-dot`} />;
|
||||
// `progressDot` enjoy the highest priority
|
||||
if (progressDot) {
|
||||
if (typeof progressDot === 'function') {
|
||||
iconNode = (
|
||||
<span class={`${prefixCls}-icon`}>
|
||||
{progressDot({
|
||||
iconDot,
|
||||
index: stepNumber - 1,
|
||||
status,
|
||||
title,
|
||||
description,
|
||||
prefixCls,
|
||||
})}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{iconDot}</span>;
|
||||
}
|
||||
} else if (icon && !isString(icon)) {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{icon}</span>;
|
||||
} else if (icons && icons.finish && status === 'finish') {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{icons.finish}</span>;
|
||||
} else if (icons && icons.error && status === 'error') {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{icons.error}</span>;
|
||||
} else if (icon || status === 'finish' || status === 'error') {
|
||||
iconNode = <span class={iconClassName} />;
|
||||
} else {
|
||||
iconNode = <span class={`${prefixCls}-icon`}>{stepNumber}</span>;
|
||||
}
|
||||
|
||||
if (stepIcon) {
|
||||
iconNode = stepIcon({
|
||||
index: stepNumber - 1,
|
||||
status,
|
||||
title,
|
||||
description,
|
||||
node: iconNode,
|
||||
});
|
||||
}
|
||||
return iconNode;
|
||||
};
|
||||
return () => {
|
||||
const {
|
||||
prefixCls,
|
||||
itemWidth,
|
||||
active,
|
||||
status = 'wait',
|
||||
tailContent,
|
||||
adjustMarginRight,
|
||||
disabled,
|
||||
title = slots.title?.(),
|
||||
description = slots.description?.(),
|
||||
subTitle = slots.subTitle?.(),
|
||||
icon = slots.icon?.(),
|
||||
onClick,
|
||||
onStepClick,
|
||||
} = props;
|
||||
|
||||
const classString = {
|
||||
[`${prefixCls}-item`]: true,
|
||||
[`${prefixCls}-item-${status}`]: true,
|
||||
[`${prefixCls}-item-custom`]: icon,
|
||||
[`${prefixCls}-item-active`]: active,
|
||||
[`${prefixCls}-item-disabled`]: disabled === true,
|
||||
};
|
||||
const stepProps = {
|
||||
class: classString,
|
||||
};
|
||||
const stepItemStyle: CSSProperties = {};
|
||||
if (itemWidth) {
|
||||
stepItemStyle.width = itemWidth;
|
||||
}
|
||||
if (adjustMarginRight) {
|
||||
stepItemStyle.marginRight = adjustMarginRight;
|
||||
}
|
||||
|
||||
const accessibilityProps: {
|
||||
role?: string;
|
||||
tabindex?: number;
|
||||
onClick?: EventHandler;
|
||||
} = {
|
||||
onClick: onClick || noop,
|
||||
};
|
||||
|
||||
if (onStepClick && !disabled) {
|
||||
accessibilityProps.role = 'button';
|
||||
accessibilityProps.tabindex = 0;
|
||||
accessibilityProps.onClick = onItemClick;
|
||||
}
|
||||
return (
|
||||
<div {...stepProps} style={stepItemStyle}>
|
||||
<div {...accessibilityProps} class={`${prefixCls}-item-container`}>
|
||||
<div class={`${prefixCls}-item-tail`}>{tailContent}</div>
|
||||
<div class={`${prefixCls}-item-icon`}>
|
||||
{renderIconNode({ icon, title, description })}
|
||||
</div>
|
||||
<div class={`${prefixCls}-item-content`}>
|
||||
<div class={`${prefixCls}-item-title`}>
|
||||
{title}
|
||||
{subTitle && (
|
||||
<div title={subTitle} class={`${prefixCls}-item-subtitle`}>
|
||||
{subTitle}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{description && <div class={`${prefixCls}-item-description`}>{description}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,170 +0,0 @@
|
|||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
import isFlexSupported from '../_util/isFlexSupported';
|
||||
import { getSlot, getPropsData } from '../_util/props-util';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Steps',
|
||||
mixins: [BaseMixin],
|
||||
props: {
|
||||
type: PropTypes.string.def('default'),
|
||||
prefixCls: PropTypes.string.def('rc-steps'),
|
||||
iconPrefix: PropTypes.string.def('rc'),
|
||||
direction: PropTypes.string.def('horizontal'),
|
||||
labelPlacement: PropTypes.string.def('horizontal'),
|
||||
status: PropTypes.string.def('process'),
|
||||
size: PropTypes.string.def(''),
|
||||
progressDot: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
|
||||
initial: PropTypes.number.def(0),
|
||||
current: PropTypes.number.def(0),
|
||||
icons: PropTypes.shape({
|
||||
finish: PropTypes.any,
|
||||
error: PropTypes.any,
|
||||
}).loose,
|
||||
canClick: PropTypes.looseBool,
|
||||
},
|
||||
data() {
|
||||
this.calcStepOffsetWidth = debounce(this.calcStepOffsetWidth, 150);
|
||||
return {
|
||||
flexSupported: true,
|
||||
lastStepOffsetWidth: 0,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.calcStepOffsetWidth();
|
||||
if (!isFlexSupported()) {
|
||||
this.setState({
|
||||
flexSupported: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
updated() {
|
||||
this.$nextTick(() => {
|
||||
this.calcStepOffsetWidth();
|
||||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.calcTimeout) {
|
||||
clearTimeout(this.calcTimeout);
|
||||
}
|
||||
if (this.calcStepOffsetWidth && this.calcStepOffsetWidth.cancel) {
|
||||
this.calcStepOffsetWidth.cancel();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onStepClick(next) {
|
||||
const { current } = this.$props;
|
||||
if (current !== next) {
|
||||
this.__emit('change', next);
|
||||
}
|
||||
},
|
||||
calcStepOffsetWidth() {
|
||||
if (isFlexSupported()) {
|
||||
return;
|
||||
}
|
||||
const { lastStepOffsetWidth } = this.$data;
|
||||
// Just for IE9
|
||||
const domNode = this.$refs.vcStepsRef;
|
||||
if (domNode.children.length > 0) {
|
||||
if (this.calcTimeout) {
|
||||
clearTimeout(this.calcTimeout);
|
||||
}
|
||||
this.calcTimeout = setTimeout(() => {
|
||||
// +1 for fit edge bug of digit width, like 35.4px
|
||||
const offsetWidth = (domNode.lastChild.offsetWidth || 0) + 1;
|
||||
// Reduce shake bug
|
||||
if (
|
||||
lastStepOffsetWidth === offsetWidth ||
|
||||
Math.abs(lastStepOffsetWidth - offsetWidth) <= 3
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.setState({ lastStepOffsetWidth: offsetWidth });
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const {
|
||||
prefixCls,
|
||||
direction,
|
||||
type,
|
||||
labelPlacement,
|
||||
iconPrefix,
|
||||
status,
|
||||
size,
|
||||
current,
|
||||
progressDot,
|
||||
initial,
|
||||
icons,
|
||||
canClick,
|
||||
} = this;
|
||||
const isNav = type === 'navigation';
|
||||
const { lastStepOffsetWidth, flexSupported } = this;
|
||||
const filteredChildren = getSlot(this);
|
||||
const lastIndex = filteredChildren.length - 1;
|
||||
const adjustedlabelPlacement = progressDot ? 'vertical' : labelPlacement;
|
||||
const classString = {
|
||||
[prefixCls]: true,
|
||||
[`${prefixCls}-${direction}`]: true,
|
||||
[`${prefixCls}-${size}`]: size,
|
||||
[`${prefixCls}-label-${adjustedlabelPlacement}`]: direction === 'horizontal',
|
||||
[`${prefixCls}-dot`]: !!progressDot,
|
||||
[`${prefixCls}-navigation`]: isNav,
|
||||
[`${prefixCls}-flex-not-supported`]: !flexSupported,
|
||||
};
|
||||
const stepsProps = {
|
||||
class: classString,
|
||||
ref: 'vcStepsRef',
|
||||
};
|
||||
return (
|
||||
<div {...stepsProps}>
|
||||
{filteredChildren.map((child, index) => {
|
||||
const childProps = getPropsData(child);
|
||||
const stepNumber = initial + index;
|
||||
const stepProps = {
|
||||
stepNumber: `${stepNumber + 1}`,
|
||||
stepIndex: stepNumber,
|
||||
prefixCls,
|
||||
iconPrefix,
|
||||
progressDot,
|
||||
icons,
|
||||
...childProps,
|
||||
};
|
||||
if (canClick) {
|
||||
stepProps.onStepClick = this.onStepClick;
|
||||
}
|
||||
if (!flexSupported && direction !== 'vertical') {
|
||||
if (isNav) {
|
||||
stepProps.itemWidth = `${100 / (lastIndex + 1)}%`;
|
||||
stepProps.adjustMarginRight = 0;
|
||||
} else if (index !== lastIndex) {
|
||||
stepProps.itemWidth = `${100 / lastIndex}%`;
|
||||
stepProps.adjustMarginRight = `${-Math.round(lastStepOffsetWidth / lastIndex + 1)}px`;
|
||||
}
|
||||
}
|
||||
// fix tail color
|
||||
if (status === 'error' && index === current - 1) {
|
||||
stepProps.class = `${prefixCls}-next-error`;
|
||||
}
|
||||
if (!childProps.status) {
|
||||
if (stepNumber === current) {
|
||||
stepProps.status = status;
|
||||
} else if (stepNumber < current) {
|
||||
stepProps.status = 'finish';
|
||||
} else {
|
||||
stepProps.status = 'wait';
|
||||
}
|
||||
}
|
||||
stepProps.active = stepNumber === current;
|
||||
return cloneElement(child, stepProps);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,122 @@
|
|||
import PropTypes from '../_util/vue-types';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import { filterEmpty } from '../_util/props-util';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { defineComponent } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
|
||||
export type Status = 'error' | 'process' | 'finish' | 'wait';
|
||||
export type StepIconRender = (info: {
|
||||
index: number;
|
||||
status: Status;
|
||||
title: any;
|
||||
description: any;
|
||||
node: any;
|
||||
}) => any;
|
||||
|
||||
export type ProgressDotRender = (info: {
|
||||
iconDot: any;
|
||||
index: number;
|
||||
status: Status;
|
||||
title: any;
|
||||
description: any;
|
||||
}) => any;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Steps',
|
||||
mixins: [BaseMixin],
|
||||
props: {
|
||||
type: PropTypes.string.def('default'),
|
||||
prefixCls: PropTypes.string.def('vc-steps'),
|
||||
iconPrefix: PropTypes.string.def('vc'),
|
||||
direction: PropTypes.string.def('horizontal'),
|
||||
labelPlacement: PropTypes.string.def('horizontal'),
|
||||
status: PropTypes.string.def('process'),
|
||||
size: PropTypes.string.def(''),
|
||||
progressDot: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func]).def(false),
|
||||
initial: PropTypes.number.def(0),
|
||||
current: PropTypes.number.def(0),
|
||||
icons: PropTypes.shape({
|
||||
finish: PropTypes.any,
|
||||
error: PropTypes.any,
|
||||
}).loose,
|
||||
stepIcon: PropTypes.func,
|
||||
},
|
||||
slots: ['stepIcon', 'progressDot'],
|
||||
emits: ['change'],
|
||||
setup(props, { slots, emit }) {
|
||||
const onStepClick = next => {
|
||||
const { current } = props;
|
||||
if (current !== next) {
|
||||
emit('change', next);
|
||||
}
|
||||
};
|
||||
return () => {
|
||||
const {
|
||||
prefixCls,
|
||||
direction,
|
||||
type,
|
||||
labelPlacement,
|
||||
iconPrefix,
|
||||
status,
|
||||
size,
|
||||
current,
|
||||
progressDot = slots.progressDot,
|
||||
initial,
|
||||
icons,
|
||||
stepIcon = slots.stepIcon,
|
||||
} = props;
|
||||
const isNav = type === 'navigation';
|
||||
const adjustedLabelPlacement = progressDot ? 'vertical' : labelPlacement;
|
||||
const classString = classNames(prefixCls, `${prefixCls}-${direction}`, {
|
||||
[`${prefixCls}-${size}`]: size,
|
||||
[`${prefixCls}-label-${adjustedLabelPlacement}`]: direction === 'horizontal',
|
||||
[`${prefixCls}-dot`]: !!progressDot,
|
||||
[`${prefixCls}-navigation`]: isNav,
|
||||
});
|
||||
const children = filterEmpty(slots.default?.());
|
||||
return (
|
||||
<div class={classString}>
|
||||
{children.map((child, index) => {
|
||||
// description: PropTypes.any,
|
||||
// icon: PropTypes.any,
|
||||
// status: PropTypes.oneOf(tuple('wait', 'process', 'finish', 'error')),
|
||||
// disabled: PropTypes.looseBool,
|
||||
// title: PropTypes.any,
|
||||
// subTitle: PropTypes.any,
|
||||
const { prefixCls: pre = prefixCls, ...restProps } = child.props || {};
|
||||
const stepNumber = initial + index;
|
||||
const stepProps = {
|
||||
...restProps,
|
||||
stepNumber: stepNumber + 1,
|
||||
stepIndex: stepNumber,
|
||||
key: stepNumber,
|
||||
prefixCls: pre,
|
||||
iconPrefix,
|
||||
progressDot,
|
||||
icons,
|
||||
stepIcon,
|
||||
onStepClick,
|
||||
};
|
||||
|
||||
// fix tail color
|
||||
if (status === 'error' && index === current - 1) {
|
||||
stepProps.class = `${prefixCls}-next-error`;
|
||||
}
|
||||
if (!restProps.status) {
|
||||
if (stepNumber === current) {
|
||||
stepProps.status = status;
|
||||
} else if (stepNumber < current) {
|
||||
stepProps.status = 'finish';
|
||||
} else {
|
||||
stepProps.status = 'wait';
|
||||
}
|
||||
}
|
||||
stepProps.active = stepNumber === current;
|
||||
return cloneElement(child, stepProps);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
|
@ -124,7 +124,7 @@ module.exports = {
|
|||
'ant-design-vue': path.join(__dirname, './components'),
|
||||
vue$: 'vue/dist/vue.runtime.esm-bundler.js',
|
||||
},
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue', '.md'],
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.md'],
|
||||
},
|
||||
devServer: {
|
||||
historyApiFallback: {
|
||||
|
|
Loading…
Reference in New Issue