vuecssuiant-designantdreactantantd-vueenterprisefrontendui-designvue-antdvue-antd-uivue3vuecomponent
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
6.4 KiB
199 lines
6.4 KiB
import PropTypes, { withUndefined } from '../_util/vue-types'; |
|
import type { CSSProperties, ExtractPropTypes } from 'vue'; |
|
import { defineComponent } from 'vue'; |
|
import type { EventHandler } from '../_util/EventInterface'; |
|
import classNames from '../_util/classNames'; |
|
import type { VueNode } from '../_util/type'; |
|
import { booleanType, stringType, functionType } from '../_util/type'; |
|
import type { StepIconRender, Status } from './interface'; |
|
import omit from '../_util/omit'; |
|
function isString(str: any): str is string { |
|
return typeof str === 'string'; |
|
} |
|
function noop() {} |
|
|
|
export const VcStepProps = () => ({ |
|
prefixCls: String, |
|
itemWidth: String, |
|
active: { type: Boolean, default: undefined }, |
|
disabled: { type: Boolean, default: undefined }, |
|
status: stringType<Status>(), |
|
iconPrefix: String, |
|
icon: PropTypes.any, |
|
adjustMarginRight: String, |
|
stepNumber: Number, |
|
stepIndex: 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: functionType(), |
|
onStepClick: functionType<(next: number) => void>(), |
|
stepIcon: functionType<StepIconRender>(), |
|
itemRender: functionType<(stepItem: VueNode) => VueNode>(), |
|
__legacy: booleanType(), |
|
}); |
|
|
|
export type VCStepProps = Partial<ExtractPropTypes<ReturnType<typeof VcStepProps>>>; |
|
export default defineComponent({ |
|
compatConfig: { MODE: 3 }, |
|
name: 'Step', |
|
inheritAttrs: false, |
|
props: VcStepProps(), |
|
setup(props, { slots, emit, attrs }) { |
|
const onItemClick: EventHandler = e => { |
|
emit('click', e); |
|
emit('stepClick', props.stepIndex); |
|
}; |
|
// if (props.__legacy !== false) { |
|
// warning( |
|
// false, |
|
// 'Steps', |
|
// 'Step is deprecated, and not support inline type. Please use `items` directly. ', |
|
// ); |
|
// } |
|
const renderIconNode = ({ icon, title, description }) => { |
|
const { |
|
prefixCls, |
|
stepNumber, |
|
status, |
|
iconPrefix, |
|
icons, |
|
progressDot = slots.progressDot, |
|
stepIcon = slots.stepIcon, |
|
} = props; |
|
|
|
let iconNode; |
|
const iconClassName = classNames(`${prefixCls}-icon`, `${iconPrefix}icon`, { |
|
[`${iconPrefix}icon-${icon}`]: icon && isString(icon), |
|
[`${iconPrefix}icon-check`]: |
|
!icon && status === 'finish' && ((icons && !icons.finish) || !icons), |
|
[`${iconPrefix}icon-cross`]: |
|
!icon && status === 'error' && ((icons && !icons.error) || !icons), |
|
}); |
|
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 mergedStatus = status || 'wait'; |
|
const classString = classNames(`${prefixCls}-item`, `${prefixCls}-item-${mergedStatus}`, { |
|
[`${prefixCls}-item-custom`]: icon, |
|
[`${prefixCls}-item-active`]: active, |
|
[`${prefixCls}-item-disabled`]: disabled === true, |
|
}); |
|
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; |
|
} |
|
const stepNode = ( |
|
<div |
|
{...omit(attrs, ['__legacy'])} |
|
class={[classString, attrs.class]} |
|
style={[attrs.style as CSSProperties, 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={typeof subTitle === 'string' ? subTitle : undefined} |
|
class={`${prefixCls}-item-subtitle`} |
|
> |
|
{subTitle} |
|
</div> |
|
)} |
|
</div> |
|
{description && <div class={`${prefixCls}-item-description`}>{description}</div>} |
|
</div> |
|
</div> |
|
</div> |
|
); |
|
if (props.itemRender) { |
|
return props.itemRender(stepNode); |
|
} |
|
return stepNode; |
|
}; |
|
}, |
|
});
|
|
|