diff --git a/breakChange-2.x.md b/breakChange-2.x.md index 91ca89edb..7fbbf9020 100644 --- a/breakChange-2.x.md +++ b/breakChange-2.x.md @@ -47,3 +47,7 @@ v-model -> v-model:selectedKeys :openKeys.sync -> v-mdoel:openKeys ## dropdown v-model -> v-model:visible + +## Steps + +v-model -> v-model:current diff --git a/components/_util/props-util.js b/components/_util/props-util.js index 5ea7f004c..700d6f377 100644 --- a/components/_util/props-util.js +++ b/components/_util/props-util.js @@ -302,6 +302,10 @@ export function getComponentName(opts) { return opts && (opts.Ctor.options.name || opts.tag); } +export function isFragment(c) { + return c.length === 1 && c[0].type === Fragment; +} + export function isEmptyElement(c) { return c.type === Comment || (c.type === Text && c.children.trim() === ''); } @@ -311,6 +315,9 @@ export function isStringElement(c) { } export function filterEmpty(children = []) { + if (isFragment(children)) { + return children[0].children.filter(c => !isEmptyElement(c)); + } return children.filter(c => !isEmptyElement(c)); } const initDefaultProps = (propTypes, defaultProps) => { diff --git a/components/steps/index.jsx b/components/steps/index.jsx index 2c60e6c81..677a5a7f4 100644 --- a/components/steps/index.jsx +++ b/components/steps/index.jsx @@ -1,10 +1,10 @@ +import { inject } from 'vue'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import CheckOutlined from '@ant-design/icons-vue/CheckOutlined'; import PropTypes from '../_util/vue-types'; -import { initDefaultProps, getOptionProps, getListeners } from '../_util/props-util'; +import { initDefaultProps, getOptionProps, getComponent } from '../_util/props-util'; import VcSteps from '../vc-steps'; import { ConfigConsumerProps } from '../config-provider'; -import Base from '../base'; const getStepsProps = (defaultProps = {}) => { const props = { @@ -27,12 +27,10 @@ const Steps = { props: getStepsProps({ current: 0, }), - inject: { - configProvider: { default: () => ConfigConsumerProps }, - }, - model: { - prop: 'current', - event: 'change', + setup() { + return { + configProvider: inject('configProvider', ConfigConsumerProps), + }; }, Step: { ...VcSteps.Step, name: 'AStep' }, render() { @@ -41,30 +39,27 @@ const Steps = { const getPrefixCls = this.configProvider.getPrefixCls; const prefixCls = getPrefixCls('steps', customizePrefixCls); const iconPrefix = getPrefixCls('', customizeIconPrefixCls); + const progressDot = getComponent(this, 'progressDot', this, false); const icons = { finish: , error: , }; const stepsProps = { - props: { - icons, - iconPrefix, - prefixCls, - ...props, - }, - on: getListeners(this), - scopedSlots: this.$scopedSlots, + icons, + iconPrefix, + prefixCls, + progressDot, + ...props, }; - return {this.$slots.default}; + return {this.$slots.default && this.$slots.default()}; }, }; /* istanbul ignore next */ -Steps.install = function(Vue) { - Vue.use(Base); - Vue.component(Steps.name, Steps); - Vue.component(Steps.Step.name, Steps.Step); +Steps.install = function(app) { + app.component(Steps.name, Steps); + app.component(Steps.Step.name, Steps.Step); }; export default Steps; diff --git a/components/vc-steps/Step.jsx b/components/vc-steps/Step.jsx index a586f4721..e7af603d6 100644 --- a/components/vc-steps/Step.jsx +++ b/components/vc-steps/Step.jsx @@ -1,5 +1,5 @@ import PropTypes from '../_util/vue-types'; -import { getOptionProps, getComponentFromProp, getListeners } from '../_util/props-util'; +import { getOptionProps, getComponent } from '../_util/props-util'; function isString(str) { return typeof str === 'string'; @@ -28,21 +28,26 @@ export default { finish: PropTypes.any, error: PropTypes.any, }).loose, + onClick: PropTypes.func, + onStepClick: PropTypes.func, }, methods: { - onClick(...args) { - this.$emit('click', ...args); + onItemClick(...args) { + const { onClick } = this.$props; + + if (onClick) { + this.$emit('click', ...args); + } + this.$emit('stepClick', this.stepIndex); }, renderIconNode() { - const { prefixCls, stepNumber, status, iconPrefix, icons } = getOptionProps(this); - let progressDot = this.progressDot; - if (progressDot === undefined) { - progressDot = this.$scopedSlots.progressDot; - } - const icon = getComponentFromProp(this, 'icon'); - const title = getComponentFromProp(this, 'title'); - const description = getComponentFromProp(this, 'description'); + 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, @@ -86,22 +91,23 @@ export default { tailContent, adjustMarginRight, disabled, + onClick, + onStepClick, } = getOptionProps(this); - const title = getComponentFromProp(this, 'title'); - const subTitle = getComponentFromProp(this, 'subTitle'); - const description = getComponentFromProp(this, 'description'); + 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`]: getComponentFromProp(this, 'icon'), + [`${prefixCls}-item-custom`]: getComponent(this, 'icon'), [`${prefixCls}-item-active`]: active, [`${prefixCls}-item-disabled`]: disabled === true, }; const stepProps = { class: classString, - on: getListeners(this), }; const stepItemStyle = {}; if (itemWidth) { @@ -110,17 +116,15 @@ export default { if (adjustMarginRight) { stepItemStyle.marginRight = adjustMarginRight; } - const listeners = getListeners(this); + const accessibilityProps = { - attrs: {}, - on: { - click: listeners.click || noop, - }, + onClick: onClick || noop, }; - if (listeners.stepClick && !disabled) { - accessibilityProps.attrs.role = 'button'; - accessibilityProps.attrs.tabIndex = 0; - accessibilityProps.on.click = this.onClick; + + if (onStepClick && !disabled) { + accessibilityProps.role = 'button'; + accessibilityProps.tabIndex = 0; + accessibilityProps.onClick = this.onItemClick; } return (
diff --git a/components/vc-steps/Steps.jsx b/components/vc-steps/Steps.jsx index 25a9cda62..b210e6efb 100644 --- a/components/vc-steps/Steps.jsx +++ b/components/vc-steps/Steps.jsx @@ -2,7 +2,7 @@ import PropTypes from '../_util/vue-types'; import BaseMixin from '../_util/BaseMixin'; import debounce from 'lodash/debounce'; import isFlexSupported from '../_util/isFlexSupported'; -import { filterEmpty, getEvents, getPropsData, getListeners } from '../_util/props-util'; +import { filterEmpty } from '../_util/props-util'; import { cloneElement } from '../_util/vnode'; export default { @@ -59,6 +59,7 @@ export default { const { current } = this.$props; if (current !== next) { this.$emit('change', next); + this.$emit('update:current', next); } }, calcStepOffsetWidth() { @@ -97,17 +98,14 @@ export default { status, size, current, - $scopedSlots, + $slots, + progressDot, initial, icons, } = this; const isNav = type === 'navigation'; - let progressDot = this.progressDot; - if (progressDot === undefined) { - progressDot = $scopedSlots.progressDot; - } const { lastStepOffsetWidth, flexSupported } = this; - const filteredChildren = filterEmpty(this.$slots.default); + const filteredChildren = filterEmpty($slots.default && $slots.default()); const lastIndex = filteredChildren.length - 1; const adjustedlabelPlacement = progressDot ? 'vertical' : labelPlacement; const classString = { @@ -119,42 +117,36 @@ export default { [`${prefixCls}-navigation`]: isNav, [`${prefixCls}-flex-not-supported`]: !flexSupported, }; - const listeners = getListeners(this); const stepsProps = { class: classString, ref: 'vcStepsRef', - on: listeners, }; return (
{filteredChildren.map((child, index) => { - const childProps = getPropsData(child); + const childProps = child.props || {}; const stepNumber = initial + index; const stepProps = { - props: { - stepNumber: `${stepNumber + 1}`, - stepIndex: stepNumber, - prefixCls, - iconPrefix, - progressDot: this.progressDot, - icons, - ...childProps, - }, - on: getEvents(child), - scopedSlots: $scopedSlots, + stepNumber: `${stepNumber + 1}`, + stepIndex: stepNumber, + prefixCls, + iconPrefix, + progressDot, + icons, + ...childProps, }; - if (listeners.change) { - stepProps.on.stepClick = this.onStepClick; + + const { onChange } = this.$attrs; + if (onChange || this.$attrs['onUpdate:current']) { + stepProps.onStepClick = this.onStepClick; } if (!flexSupported && direction !== 'vertical') { if (isNav) { - stepProps.props.itemWidth = `${100 / (lastIndex + 1)}%`; - stepProps.props.adjustMarginRight = 0; + stepProps.itemWidth = `${100 / (lastIndex + 1)}%`; + stepProps.adjustMarginRight = 0; } else if (index !== lastIndex) { - stepProps.props.itemWidth = `${100 / lastIndex}%`; - stepProps.props.adjustMarginRight = `${-Math.round( - lastStepOffsetWidth / lastIndex + 1, - )}px`; + stepProps.itemWidth = `${100 / lastIndex}%`; + stepProps.adjustMarginRight = `${-Math.round(lastStepOffsetWidth / lastIndex + 1)}px`; } } // fix tail color @@ -163,14 +155,14 @@ export default { } if (!childProps.status) { if (stepNumber === current) { - stepProps.props.status = status; + stepProps.status = status; } else if (stepNumber < current) { - stepProps.props.status = 'finish'; + stepProps.status = 'finish'; } else { - stepProps.props.status = 'wait'; + stepProps.status = 'wait'; } } - stepProps.props.active = stepNumber === current; + stepProps.active = stepNumber === current; return cloneElement(child, stepProps); })}
diff --git a/examples/index.js b/examples/index.js index 9f0851cfd..a7e80cb3b 100644 --- a/examples/index.js +++ b/examples/index.js @@ -33,6 +33,7 @@ import Modal from 'ant-design-vue/modal'; import Menu from 'ant-design-vue/menu'; import Mentions from 'ant-design-vue/mentions'; import Dropdown from 'ant-design-vue/dropdown'; +import Steps from 'ant-design-vue/steps'; import 'ant-design-vue/style.js'; const basic = { @@ -79,4 +80,5 @@ app .use(Menu) .use(Mentions) .use(Dropdown) + .use(Steps) .mount('#app');