diff --git a/.eslintignore b/.eslintignore
index 4c64b6f77..0c337a6d9 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,3 +2,4 @@ node_modules/
**/*.spec.*
**/style/
*.html
+/components/test/*
diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md
index fc095d189..9491b0bfb 100644
--- a/CHANGELOG.en-US.md
+++ b/CHANGELOG.en-US.md
@@ -2,6 +2,40 @@
---
+## 1.2.0
+`2018-12-16`
+### Synchronize with antd 3.10.x
+
+- 🔥🔥🔥 replaced font icons with svg icons which bring benefits below::
+ - Complete offline usage of icon, no dependency of alipay cdn font icon file and no more empty square during downloading than no need to deploy icon font files locally either.
+ - Much more display accuracy in lower-level screens.
+ - Support multiple colors for icon.
+ - No need to change built-in icons with overriding styles by providing more props in component.
+ - 🌟 Add the `theme` attribute to set the theme style of the icon.
+ - 🌟 Added `component` attribute, you can externally pass a component to customize the control rendering result.
+ - 🌟 The `twoToneColor` property is added to control the theme color of the two-color icon.
+ - 🌟 Added static methods `Icon.getTowToneColor()` and `Icon.setTwoToneColor(...)` to globally get and set the theme color of all two-color icons.
+ - 🌟 The new static method `Icon.createFromIconfontCN({...})` is added to make it easier to use icons hosted on [`iconfont.cn`](http://iconfont.cn/).
+- 🔥 Added a new component `Skeleton`.
+- 🔥 Menu will automatically close up to fit width in `horizontal` mode.
+- 🔥 The `placement` of the drawer supports `top` and `bottom` to accommodate more scenes.
+- 🌟 The following components add a `suffixIcon` prop, which is used to set the icon behind the input box. For details, please refer to the documentation.
+ - Cascader
+ - DatePicker
+ - Select
+ - TreeSelect
+ - TimePicker
+- 🌟 Added Modal.open for optional icon dialog.
+- 🌟 Modal.info adds the configuration of `getContainer`.
+- 🌟 Improve RangePicker footer UI by merging them.
+- 🌟 The Anchor component adds `onClick` property.
+- 🌟 The Tab component adds the `renderTabBar` property.
+- 🌟 The Input component adds the `select` method.
+- 🌟 Steps adds the `initial` attribute.
+- 🌟 Upload adds `openFileDialogOnClick` prop to allow setting whether to open the upload dialog when the component is clicked.
+- 🌟 InputNumber adds `decimalSeparator` prop to allow setting a custom decimal.
+- 🐞 Fix a lot of hidden bugs that have not yet been issued, and then not list them one by one.
+
## 1.1.10
`2018-12-7`
diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md
index b49d7f92a..e1639ced3 100644
--- a/CHANGELOG.zh-CN.md
+++ b/CHANGELOG.zh-CN.md
@@ -2,6 +2,40 @@
---
+## 1.2.0
+`2018-12-16`
+### 与antd 3.10.x同步
+
+- 🔥🔥🔥 使用了 svg 图标替换了原先的 font 图标,从而带来了以下优势:
+ 可以离线化使用,不需要从支付宝 cdn 下载字体文件,图标不会因为网络问题呈现方块,也无需字体文件本地部署。
+ 在低端设备上 svg 有更好的清晰度。
+ 支持多色图标。
+ 对于内建图标的更换可以提供更多 API,而不需要进行样式覆盖。
+ - 🌟 新增 `theme` 属性,可以设置图标的主题风格。
+ - 🌟 新增 `component` 属性,可以外部传入一个组件来自定义控制渲染结果。
+ - 🌟 新增 `twoToneColor` 属性,可以控制双色图标的主题色。
+ - 🌟 新增静态方法 `Icon.getTowToneColor()` 和 `Icon.setTwoToneColor(...)`,可以全局性的获取和设置所有双色图标的主题色。
+ - 🌟 新增静态方法 `Icon.createFromIconfontCN({...})`,可以更加方便地使用 [`iconfont.cn`](http://iconfont.cn/) 上托管的图标。
+- 🔥 增加了一个新组件`Skeleton`
+- 🔥 Menu 在 `horizontal` 模式下会自动收起来适应宽度。
+- 🔥 Drawer 的 `placement` 支持 `top` 和 `bottom`,可以适应更多场景。
+- 🌟 以下组件均新增了 `suffixIcon` 属性,用于设置输入框后面的图标,具体用法可以参考文档。
+ - Cascader
+ - DatePicker
+ - Select
+ - TreeSelect
+ - TimePicker
+- 🌟 新增 Modal.open 方法,用于可自定义图标的快捷对话框。
+- 🌟 Modal.info 增加 `getContainer` 的配置。
+- 🌟 合并优化了 RangePicker 的日历页脚 UI。
+- 🌟 Anchor 组件增加 `click` 事件。
+- 🌟 Tab 组件增加 `renderTabBar` 属性。
+- 🌟 Input 组件增加 `select` 方法。
+- 🌟 Steps 增加 `initial` 属性。
+- 🌟 Upload 组件新增 `openFileDialogOnClick` 属性,用于设置点击组件时是否打开上传对话框。
+- 🌟 InputNumber 组件新增 `decimalSeparator` 属性,用于设置自定义的小数点。
+- 🐞 修复众多隐蔽暂未提issue的bug,再此不在一一列出
+
## 1.1.10
`2018-12-7`
diff --git a/components/_util/FormDecoratorDirective.js b/components/_util/FormDecoratorDirective.js
index 1fc7ecf23..746f9dc4c 100644
--- a/components/_util/FormDecoratorDirective.js
+++ b/components/_util/FormDecoratorDirective.js
@@ -1,7 +1,11 @@
+export function antDecorator (Vue) {
+ return Vue.directive('decorator', {
+ })
+}
+
export default {
// just for tag
install: (Vue, options) => {
- Vue.directive('decorator', {
- })
+ antDecorator(Vue)
},
}
diff --git a/components/_util/antDirective.js b/components/_util/antDirective.js
new file mode 100644
index 000000000..fb89c3135
--- /dev/null
+++ b/components/_util/antDirective.js
@@ -0,0 +1,9 @@
+import { antInput } from './antInputDirective'
+import { antDecorator } from './FormDecoratorDirective'
+
+export default {
+ install: (Vue, options) => {
+ antInput(Vue)
+ antDecorator(Vue)
+ },
+}
diff --git a/components/_util/antInputDirective.js b/components/_util/antInputDirective.js
index c6812322e..aeba9f943 100644
--- a/components/_util/antInputDirective.js
+++ b/components/_util/antInputDirective.js
@@ -49,26 +49,30 @@ if (isIE9) {
})
}
-export default {
- install: (Vue, options) => {
- Vue.directive('ant-input', {
- inserted (el, binding, vnode, oldVnode) {
- if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
- if (!binding.modifiers || !binding.modifiers.lazy) {
- el.addEventListener('compositionstart', onCompositionStart)
- el.addEventListener('compositionend', onCompositionEnd)
- // Safari < 10.2 & UIWebView doesn't fire compositionend when
- // switching focus before confirming composition choice
- // this also fixes the issue where some browsers e.g. iOS Chrome
- // fires "change" instead of "input" on autocomplete.
- el.addEventListener('change', onCompositionEnd)
- /* istanbul ignore if */
- if (isIE9) {
- el.vmodel = true
- }
+export function antInput (Vue) {
+ return Vue.directive('ant-input', {
+ inserted (el, binding, vnode, oldVnode) {
+ if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
+ if (!binding.modifiers || !binding.modifiers.lazy) {
+ el.addEventListener('compositionstart', onCompositionStart)
+ el.addEventListener('compositionend', onCompositionEnd)
+ // Safari < 10.2 & UIWebView doesn't fire compositionend when
+ // switching focus before confirming composition choice
+ // this also fixes the issue where some browsers e.g. iOS Chrome
+ // fires "change" instead of "input" on autocomplete.
+ el.addEventListener('change', onCompositionEnd)
+ /* istanbul ignore if */
+ if (isIE9) {
+ el.vmodel = true
}
}
- },
- })
+ }
+ },
+ })
+}
+
+export default {
+ install: (Vue, options) => {
+ antInput(Vue)
},
}
diff --git a/components/_util/antRefDirective.js b/components/_util/antRefDirective.js
deleted file mode 100644
index c7e3b7425..000000000
--- a/components/_util/antRefDirective.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export default {
- install: (Vue, options) => {
- Vue.directive('ant-ref', {
- bind: function (el, binding, vnode) {
- binding.value(vnode.componentInstance ? vnode.componentInstance : vnode.elm)
- },
- update: function (el, binding, vnode) {
- binding.value(vnode.componentInstance ? vnode.componentInstance : vnode.elm)
- },
- unbind: function (el, binding, vnode) {
- binding.value(null)
- },
- })
- },
-}
diff --git a/components/_util/css-animation/Event.js b/components/_util/css-animation/Event.js
index 06e69a471..d35c67345 100644
--- a/components/_util/css-animation/Event.js
+++ b/components/_util/css-animation/Event.js
@@ -1,4 +1,22 @@
-const EVENT_NAME_MAP = {
+const START_EVENT_NAME_MAP = {
+ transitionstart: {
+ transition: 'transitionstart',
+ WebkitTransition: 'webkitTransitionStart',
+ MozTransition: 'mozTransitionStart',
+ OTransition: 'oTransitionStart',
+ msTransition: 'MSTransitionStart',
+ },
+
+ animationstart: {
+ animation: 'animationstart',
+ WebkitAnimation: 'webkitAnimationStart',
+ MozAnimation: 'mozAnimationStart',
+ OAnimation: 'oAnimationStart',
+ msAnimation: 'MSAnimationStart',
+ },
+}
+
+const END_EVENT_NAME_MAP = {
transitionend: {
transition: 'transitionend',
WebkitTransition: 'webkitTransitionEnd',
@@ -16,6 +34,7 @@ const EVENT_NAME_MAP = {
},
}
+const startEvents = []
const endEvents = []
function detectEvents () {
@@ -23,24 +42,31 @@ function detectEvents () {
const style = testEl.style
if (!('AnimationEvent' in window)) {
- delete EVENT_NAME_MAP.animationend.animation
+ delete START_EVENT_NAME_MAP.animationstart.animation
+ delete END_EVENT_NAME_MAP.animationend.animation
}
if (!('TransitionEvent' in window)) {
- delete EVENT_NAME_MAP.transitionend.transition
+ delete START_EVENT_NAME_MAP.transitionstart.transition
+ delete END_EVENT_NAME_MAP.transitionend.transition
}
- for (const baseEventName in EVENT_NAME_MAP) {
- if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) {
- const baseEvents = EVENT_NAME_MAP[baseEventName]
- for (const styleName in baseEvents) {
- if (styleName in style) {
- endEvents.push(baseEvents[styleName])
- break
+ function process (EVENT_NAME_MAP, events) {
+ for (const baseEventName in EVENT_NAME_MAP) {
+ if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) {
+ const baseEvents = EVENT_NAME_MAP[baseEventName]
+ for (const styleName in baseEvents) {
+ if (styleName in style) {
+ events.push(baseEvents[styleName])
+ break
+ }
}
}
}
}
+
+ process(START_EVENT_NAME_MAP, startEvents)
+ process(END_EVENT_NAME_MAP, endEvents)
}
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
@@ -56,6 +82,31 @@ function removeEventListener (node, eventName, eventListener) {
}
const TransitionEvents = {
+ // Start events
+ startEvents,
+
+ addStartEventListener (node, eventListener) {
+ if (startEvents.length === 0) {
+ window.setTimeout(eventListener, 0)
+ return
+ }
+ startEvents.forEach((startEvent) => {
+ addEventListener(node, startEvent, eventListener)
+ })
+ },
+
+ removeStartEventListener (node, eventListener) {
+ if (startEvents.length === 0) {
+ return
+ }
+ startEvents.forEach((startEvent) => {
+ removeEventListener(node, startEvent, eventListener)
+ })
+ },
+
+ // End events
+ endEvents,
+
addEndEventListener (node, eventListener) {
if (endEvents.length === 0) {
window.setTimeout(eventListener, 0)
@@ -66,8 +117,6 @@ const TransitionEvents = {
})
},
- endEvents,
-
removeEndEventListener (node, eventListener) {
if (endEvents.length === 0) {
return
@@ -79,4 +128,3 @@ const TransitionEvents = {
}
export default TransitionEvents
-
diff --git a/components/_util/css-animation/index.js b/components/_util/css-animation/index.js
index 252b49d24..0766ff613 100644
--- a/components/_util/css-animation/index.js
+++ b/components/_util/css-animation/index.js
@@ -1,3 +1,5 @@
+// https://github.com/yiminghe/css-animation 1.5.0
+
import Event from './Event'
import classes from 'component-classes'
import { requestAnimationTimeout, cancelAnimationTimeout } from '../requestAnimationTimeout'
diff --git a/components/_util/props-util.js b/components/_util/props-util.js
index a8304000e..9da6e289f 100644
--- a/components/_util/props-util.js
+++ b/components/_util/props-util.js
@@ -95,19 +95,22 @@ const getOptionProps = (instance) => {
return filterProps($props, $options.propsData)
}
-const getComponentFromProp = (instance, prop) => {
+const getComponentFromProp = (instance, prop, options = instance, execute = true) => {
if (instance.$createElement) {
const h = instance.$createElement
const temp = instance[prop]
if (temp !== undefined) {
- return typeof temp === 'function' ? temp(h) : temp
+ return typeof temp === 'function' && execute ? temp(h, options) : temp
}
- return instance.$slots[prop]
+ return instance.$slots[prop] ||
+ (instance.$scopedSlots[prop] && execute && instance.$scopedSlots[prop](options)) ||
+ (instance.$scopedSlots[prop] && instance.$scopedSlots[prop]) ||
+ undefined
} else {
const h = instance.context.$createElement
const temp = getPropsData(instance)[prop]
if (temp !== undefined) {
- return typeof temp === 'function' ? temp(h) : temp
+ return typeof temp === 'function' && execute ? temp(h, options) : temp
}
const slotsProp = []
const componentOptions = instance.componentOptions || {};
@@ -231,7 +234,7 @@ const initDefaultProps = (propTypes, defaultProps) => {
export function mergeProps () {
const args = [].slice.call(arguments, 0)
const props = {}
- args.forEach((p, i) => {
+ args.forEach((p = {}, i) => {
for (const [k, v] of Object.entries(p)) {
props[k] = props[k] || {}
if (isPlainObject(v)) {
diff --git a/components/_util/raf.js b/components/_util/raf.js
new file mode 100644
index 000000000..ef632d25b
--- /dev/null
+++ b/components/_util/raf.js
@@ -0,0 +1,30 @@
+import raf from 'raf'
+
+let id = 0
+const ids = {}
+
+// Support call raf with delay specified frame
+export default function wrapperRaf (callback, delayFrames = 1) {
+ const myId = id++
+ let restFrames = delayFrames
+
+ function internalCallback () {
+ restFrames -= 1
+
+ if (restFrames <= 0) {
+ callback()
+ delete ids[id]
+ } else {
+ ids[id] = raf(internalCallback)
+ }
+ }
+
+ ids[id] = raf(internalCallback)
+
+ return myId
+}
+
+wrapperRaf.cancel = function (id) {
+ raf.cancel(ids[id])
+ delete ids[id]
+}
diff --git a/components/_util/store/connect.jsx b/components/_util/store/connect.jsx
index 05601589d..0bce77360 100644
--- a/components/_util/store/connect.jsx
+++ b/components/_util/store/connect.jsx
@@ -26,6 +26,7 @@ export default function connect (mapStateToProps) {
},
data () {
this.store = this.storeContext.store
+ this.preProps = { ...omit(getOptionProps(this), ['__propsSymbol__']) }
return {
subscribed: finnalMapStateToProps(this.store.getState(), this.$props),
}
@@ -49,10 +50,10 @@ export default function connect (mapStateToProps) {
if (!this.unsubscribe) {
return
}
-
- const nextState = finnalMapStateToProps(this.store.getState(), this.$props)
- if (!shallowEqual(this.subscribed, nextState)) {
- this.subscribed = nextState
+ const props = getOptionProps(this)
+ const nextSubscribed = finnalMapStateToProps(this.store.getState(), props)
+ if (!shallowEqual(this.preProps, props) || !shallowEqual(this.subscribed, nextSubscribed)) {
+ this.subscribed = nextSubscribed
}
},
@@ -74,8 +75,10 @@ export default function connect (mapStateToProps) {
},
},
render () {
+ this.preProps = { ...this.$props }
const { $listeners, $slots = {}, $attrs, $scopedSlots, subscribed, store } = this
const props = getOptionProps(this)
+ this.preProps = { ...omit(props, ['__propsSymbol__']) }
const wrapProps = {
props: {
...props,
diff --git a/components/_util/vnode.js b/components/_util/vnode.js
index 06b6235a1..7d5e01603 100644
--- a/components/_util/vnode.js
+++ b/components/_util/vnode.js
@@ -51,7 +51,7 @@ export function cloneVNodes (vnodes, deep) {
return res
}
-export function cloneElement (n, nodeProps, deep) {
+export function cloneElement (n, nodeProps = {}, deep) {
let ele = n
if (Array.isArray(n)) {
ele = filterEmpty(n)[0]
diff --git a/components/_util/wave.jsx b/components/_util/wave.jsx
index 82d4c733f..ac262e156 100644
--- a/components/_util/wave.jsx
+++ b/components/_util/wave.jsx
@@ -1,12 +1,26 @@
import TransitionEvents from './css-animation/Event'
+import raf from '../_util/raf'
+let styleForPesudo
+
+// Where el is the DOM element you'd like to test for visibility
+function isHidden (element) {
+ if (process.env.NODE_ENV === 'test') {
+ return false
+ }
+ return !element || element.offsetParent === null
+}
export default {
name: 'Wave',
props: ['insertExtraNode'],
mounted () {
this.$nextTick(() => {
- this.instance = this.bindAnimationEvent(this.$el)
+ const node = this.$el
+ if (node.nodeType !== 1) {
+ return
+ }
+ this.instance = this.bindAnimationEvent(node)
})
},
@@ -14,6 +28,10 @@ export default {
if (this.instance) {
this.instance.cancel()
}
+ if (this.clickWaveTimeoutId) {
+ clearTimeout(this.clickWaveTimeoutId)
+ }
+ this.destroy = true
},
methods: {
isNotGrey (color) {
@@ -25,7 +43,7 @@ export default {
},
onClick (node, waveColor) {
- if (node.className.indexOf('-leave') >= 0) {
+ if (!node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
return
}
this.removeExtraStyleNode()
@@ -37,6 +55,7 @@ export default {
node.removeAttribute(attributeName)
node.setAttribute(attributeName, 'true')
// Not white or transparnt or grey
+ styleForPesudo = styleForPesudo || document.createElement('style')
if (waveColor &&
waveColor !== '#ffffff' &&
waveColor !== 'rgb(255, 255, 255)' &&
@@ -44,14 +63,17 @@ export default {
!/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color
waveColor !== 'transparent') {
extraNode.style.borderColor = waveColor
- this.styleForPesudo = document.createElement('style')
- this.styleForPesudo.innerHTML =
+
+ styleForPesudo.innerHTML =
`[ant-click-animating-without-extra-node]:after { border-color: ${waveColor}; }`
- document.body.appendChild(this.styleForPesudo)
+ if (!document.body.contains(styleForPesudo)) {
+ document.body.appendChild(styleForPesudo)
+ }
}
if (insertExtraNode) {
node.appendChild(extraNode)
}
+ TransitionEvents.addStartEventListener(node, this.onTransitionStart)
TransitionEvents.addEndEventListener(node, this.onTransitionEnd)
},
@@ -64,7 +86,7 @@ export default {
}
const onClick = (e) => {
// Fix radio button click twice
- if (e.target.tagName === 'INPUT') {
+ if (e.target.tagName === 'INPUT' || isHidden(e.target)) {
return
}
this.resetEffect(node)
@@ -74,6 +96,13 @@ export default {
getComputedStyle(node).getPropertyValue('border-color') ||
getComputedStyle(node).getPropertyValue('background-color')
this.clickWaveTimeoutId = window.setTimeout(() => this.onClick(node, waveColor), 0)
+ raf.cancel(this.animationStartId)
+ this.animationStart = true
+
+ // Render to trigger transition event cost 3 frames. Let's delay 10 frames to reset this.
+ this.animationStartId = raf(() => {
+ this.animationStart = false
+ }, 10)
}
node.addEventListener('click', onClick, true)
return {
@@ -98,9 +127,21 @@ export default {
if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
node.removeChild(this.extraNode)
}
+ TransitionEvents.removeStartEventListener(node, this.onTransitionStart)
TransitionEvents.removeEndEventListener(node, this.onTransitionEnd)
},
+ onTransitionStart (e) {
+ if (this.destroy) return
+ const node = this.$el
+ if (!e || e.target !== node) {
+ return
+ }
+
+ if (!this.animationStart) {
+ this.resetEffect(node)
+ }
+ },
onTransitionEnd (e) {
if (!e || e.animationName !== 'fadeEffect') {
return
@@ -108,9 +149,8 @@ export default {
this.resetEffect(e.target)
},
removeExtraStyleNode () {
- if (this.styleForPesudo && document.body.contains(this.styleForPesudo)) {
- document.body.removeChild(this.styleForPesudo)
- this.styleForPesudo = null
+ if (styleForPesudo) {
+ styleForPesudo.innerHTML = ''
}
},
},
diff --git a/components/affix/demo/index.vue b/components/affix/demo/index.vue
index ef83a3199..d953c643f 100644
--- a/components/affix/demo/index.vue
+++ b/components/affix/demo/index.vue
@@ -21,6 +21,7 @@ Please note that Affix should not cover other content on the page, especially wh
export default {
category: 'Components',
subtitle: '固钉',
+ zhType: '导航',
type: 'Navigation',
title: 'Affix',
render () {
diff --git a/components/affix/index.jsx b/components/affix/index.jsx
index 8aade3b47..a9fb0b25b 100644
--- a/components/affix/index.jsx
+++ b/components/affix/index.jsx
@@ -147,8 +147,8 @@ const Affix = {
},
updatePosition (e) {
- let { offsetTop } = this
const { offsetBottom, offset, target = getDefaultTarget } = this
+ let { offsetTop } = this
const targetNode = target()
// Backwards support
diff --git a/components/alert/__tests__/__snapshots__/demo.test.js.snap b/components/alert/__tests__/__snapshots__/demo.test.js.snap
index 23160bc1e..b42763a71 100644
--- a/components/alert/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/alert/__tests__/__snapshots__/demo.test.js.snap
@@ -2,10 +2,18 @@
exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
-
Warning text
-
Very long warning text warning text text text text text text text
+
+
+
+ Very long warning text warning text text text text text text text
+
+
Warning text without icon
-
Error text
+
`;
@@ -13,13 +21,31 @@ exports[`renders ./components/alert/demo/basic.md correctly 1`] = `
-
Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text
-
Error Text Error Description Error Description Error Description Error Description Error Description Error Description
+
Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text
+
+
+
Error Text Error Description Error Description Error Description Error Description Error Description Error Description
+
+
`;
exports[`renders ./components/alert/demo/close-text.md correctly 1`] = ``;
+exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
+
+
showIcon = false
+
+
+
+
+
Success Tips Detailed description and advices about successful copywriting.
+
Informational Notes Additional description and informations about copywriting.
+
Warning This is a warning notice about copywriting.
+
Error This is an error message about copywriting.
+
+`;
+
exports[`renders ./components/alert/demo/description.md correctly 1`] = `
Success Text
@@ -33,20 +59,42 @@ exports[`renders ./components/alert/demo/description.md correctly 1`] = `
exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
-
Success Tips
-
Informational Notes
-
Warning
-
Error
-
Success Tips Detailed description and advices about successful copywriting.
-
Informational Notes Additional description and informations about copywriting.
-
Warning This is a warning notice about copywriting.
-
Error This is an error message about copywriting.
+
+
+
+
+
+
+
+ Success Tips Detailed description and advices about successful copywriting.
+
+
+
+ Informational Notes Additional description and informations about copywriting.
+
+
+
+ Warning This is a warning notice about copywriting.
+
+
+
+ Error This is an error message about copywriting.
`;
exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
`;
diff --git a/components/alert/demo/custom-icon.md b/components/alert/demo/custom-icon.md
new file mode 100644
index 000000000..1b74407a6
--- /dev/null
+++ b/components/alert/demo/custom-icon.md
@@ -0,0 +1,63 @@
+
+#### 自定义图标
+可口的图标让信息类型更加醒目。
+
+
+
+#### Custom Icon
+Decent icon make information more clear and more friendly.
+
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/components/alert/demo/index.vue b/components/alert/demo/index.vue
index 92d6be4db..9d693b75f 100644
--- a/components/alert/demo/index.vue
+++ b/components/alert/demo/index.vue
@@ -29,6 +29,7 @@ export default {
category: 'Components',
subtitle: '警告提示',
type: 'Feedback',
+ zhType: '反馈',
title: 'Alert',
render () {
return (
diff --git a/components/alert/demo/smooth-closed.md b/components/alert/demo/smooth-closed.md
index 2fe9bcc99..bb51e5654 100644
--- a/components/alert/demo/smooth-closed.md
+++ b/components/alert/demo/smooth-closed.md
@@ -1,6 +1,6 @@
#### 平滑地卸载
-平滑、自然的卸载提示
+平滑、自然的卸载提示。
diff --git a/components/alert/index.en-US.md b/components/alert/index.en-US.md
index 127d8cbd1..b59801449 100644
--- a/components/alert/index.en-US.md
+++ b/components/alert/index.en-US.md
@@ -8,7 +8,7 @@
| closable | Whether Alert can be closed | boolean | - |
| closeText | Close text to show | string\|slot | - |
| description | Additional content of Alert | string\|slot | - |
-| iconType | Icon type, effective when `showIcon` is `true` | string | - |
+| icon | Custom icon, effective when `showIcon` is `true` | vnode \| slot | - |
| message | Content of Alert | string\|slot | - |
| showIcon | Whether to show icon | boolean | false, in `banner` mode default is true |
| type | Type of Alert styles, options: `success`, `info`, `warning`, `error` | string | `info`, in `banner` mode default is `warning` |
diff --git a/components/alert/index.jsx b/components/alert/index.jsx
index 9f9512569..a02b244a1 100644
--- a/components/alert/index.jsx
+++ b/components/alert/index.jsx
@@ -4,7 +4,8 @@ import classNames from 'classnames'
import BaseMixin from '../_util/BaseMixin'
import PropTypes from '../_util/vue-types'
import getTransitionProps from '../_util/getTransitionProps'
-import { getComponentFromProp } from '../_util/props-util'
+import { getComponentFromProp, isValidElement } from '../_util/props-util'
+import { cloneElement } from '../_util/vnode'
function noop () { }
export const AlertProps = {
/**
@@ -28,6 +29,7 @@ export const AlertProps = {
iconType: PropTypes.string,
prefixCls: PropTypes.string,
banner: PropTypes.bool,
+ icon: PropTypes.any,
}
const Alert = {
@@ -69,11 +71,14 @@ const Alert = {
const closeText = getComponentFromProp(this, 'closeText')
const description = getComponentFromProp(this, 'description')
const message = getComponentFromProp(this, 'message')
+ const icon = getComponentFromProp(this, 'icon')
// banner模式默认有 Icon
showIcon = banner && showIcon === undefined ? true : showIcon
// banner模式默认为警告
type = banner && type === undefined ? 'warning' : type || 'info'
-
+ let iconTheme = 'filled'
+ // should we give a warning?
+ // warning(!iconType, `The property 'iconType' is deprecated. Use the property 'icon' instead.`);
if (!iconType) {
switch (type) {
case 'success':
@@ -83,7 +88,7 @@ const Alert = {
iconType = 'info-circle'
break
case 'error':
- iconType = 'cross-circle'
+ iconType = 'close-circle'
break
case 'warning':
iconType = 'exclamation-circle'
@@ -94,7 +99,7 @@ const Alert = {
// use outline icon in alert with description
if (description) {
- iconType += '-o'
+ iconTheme = 'outlined'
}
}
@@ -113,9 +118,21 @@ const Alert = {
const closeIcon = closable ? (
- {closeText || }
+ {closeText || }
) : null
+
+ const iconNode = icon && (
+ isValidElement(icon)
+ ? cloneElement(
+ icon,
+ {
+ class: `${prefixCls}-icon`,
+ },
+ ) : {icon} ) || (
+
+ )
+
const transitionProps = getTransitionProps(`${prefixCls}-slide-up`, {
appear: false,
afterLeave: this.animationEnd,
@@ -123,7 +140,7 @@ const Alert = {
return closed ? null : (
- {showIcon ?
: null}
+ {showIcon ? iconNode : null}
{message}
{description}
{closeIcon}
diff --git a/components/alert/index.zh-CN.md b/components/alert/index.zh-CN.md
index d3d16725a..5393b048b 100644
--- a/components/alert/index.zh-CN.md
+++ b/components/alert/index.zh-CN.md
@@ -8,7 +8,7 @@
| closable | 默认不显示关闭按钮 | boolean | 无 |
| closeText | 自定义关闭按钮 | string\|slot | 无 |
| description | 警告提示的辅助性文字介绍 | string\|slot | 无 |
-| iconType | 自定义图标类型,`showIcon` 为 `true` 时有效 | string | - |
+| icon | 自定义图标,`showIcon` 为 `true` 时有效 | vnode \| slot | - |
| message | 警告提示内容 | string\|slot | 无 |
| showIcon | 是否显示辅助图标 | boolean | false,`banner` 模式下默认值为 true |
| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | string | `info`,`banner` 模式下默认值为 `warning` |
diff --git a/components/alert/style/index.less b/components/alert/style/index.less
index a5654533a..a876d6921 100644
--- a/components/alert/style/index.less
+++ b/components/alert/style/index.less
@@ -18,7 +18,7 @@
}
&-icon {
- top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2 + 1px;
+ top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2;
left: 16px;
position: absolute;
}
@@ -30,34 +30,34 @@
}
&-success {
- border: @border-width-base @border-style-base ~`colorPalette("@{success-color}", 3)`;
- background-color: ~`colorPalette("@{success-color}", 1)`;
+ border: @border-width-base @border-style-base @alert-success-border-color;
+ background-color: @alert-success-bg-color;
.@{alert-prefix-cls}-icon {
- color: @success-color;
+ color: @alert-success-icon-color;
}
}
&-info {
- border: @border-width-base @border-style-base ~`colorPalette("@{info-color}", 3)`;
- background-color: ~`colorPalette("@{info-color}", 1)`;
+ border: @border-width-base @border-style-base @alert-info-border-color;
+ background-color: @alert-info-bg-color;
.@{alert-prefix-cls}-icon {
- color: @info-color;
+ color: @alert-info-icon-color;
}
}
&-warning {
- border: @border-width-base @border-style-base ~`colorPalette("@{warning-color}", 3)`;
- background-color: ~`colorPalette("@{warning-color}", 1)`;
+ border: @border-width-base @border-style-base @alert-warning-border-color;
+ background-color: @alert-warning-bg-color;
.@{alert-prefix-cls}-icon {
- color: @warning-color;
+ color: @alert-warning-icon-color;
}
}
&-error {
- border: @border-width-base @border-style-base ~`colorPalette("@{error-color}", 3)`;
- background-color: ~`colorPalette("@{error-color}", 1)`;
+ border: @border-width-base @border-style-base @alert-error-border-color;
+ background-color: @alert-error-bg-color;
.@{alert-prefix-cls}-icon {
- color: @error-color;
+ color: @alert-error-icon-color;
}
}
@@ -70,7 +70,7 @@
overflow: hidden;
cursor: pointer;
- .@{iconfont-css-prefix}-cross {
+ .@{iconfont-css-prefix}-close {
color: @alert-close-color;
transition: color .3s;
&:hover {
diff --git a/components/anchor/Anchor.jsx b/components/anchor/Anchor.jsx
index bc469b038..a0ea8be4a 100644
--- a/components/anchor/Anchor.jsx
+++ b/components/anchor/Anchor.jsx
@@ -4,7 +4,7 @@ import addEventListener from '../_util/Dom/addEventListener'
import Affix from '../affix'
import getScroll from '../_util/getScroll'
import raf from 'raf'
-import { initDefaultProps, getClass, getStyle } from '../_util/props-util'
+import { initDefaultProps, getClass } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
function getDefaultContainer () {
@@ -71,7 +71,6 @@ function scrollTo (href, offsetTop = 0, getContainer, callback = () => { }) {
}
}
raf(frameFunc)
- history.pushState(null, '', href)
}
export const AnchorProps = {
@@ -117,6 +116,7 @@ export default {
$data: this.$data,
scrollTo: this.handleScrollTo,
},
+ antAnchorContext: this,
}
},
diff --git a/components/anchor/AnchorLink.jsx b/components/anchor/AnchorLink.jsx
index 92ab3cbb9..eebad878e 100644
--- a/components/anchor/AnchorLink.jsx
+++ b/components/anchor/AnchorLink.jsx
@@ -16,6 +16,7 @@ export default {
}),
inject: {
antAnchor: { default: {}},
+ antAnchorContext: { default: {}},
},
mounted () {
@@ -32,8 +33,14 @@ export default {
},
},
methods: {
- handleClick () {
+ handleClick (e) {
this.antAnchor.scrollTo(this.href)
+ const { scrollTo } = this.antAnchor
+ const { href, title } = this.$props
+ if (this.antAnchorContext.$emit) {
+ this.antAnchorContext.$emit('click', e, { title, href })
+ }
+ scrollTo(href)
},
},
render () {
diff --git a/components/anchor/__tests__/Anchor.test.js b/components/anchor/__tests__/Anchor.test.js
index faf97f3c8..bc3aa0bde 100644
--- a/components/anchor/__tests__/Anchor.test.js
+++ b/components/anchor/__tests__/Anchor.test.js
@@ -151,4 +151,31 @@ describe('Anchor Render', () => {
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API_1'])
})
})
+
+ it('Anchor onClick event', () => {
+ let event
+ let link
+ const handleClick = (...arg) => ([event, link] = arg)
+
+ const href = '#API'
+ const title = 'API'
+
+ const wrapper = mount(
+ {
+ render () {
+ return (
+
+
+
+ )
+ },
+ }
+ )
+
+ wrapper.find(`a[href="${href}"]`).trigger('click')
+
+ wrapper.vm.$refs.anchorRef.handleScroll()
+ expect(event).not.toBe(undefined)
+ expect(link).toEqual({ href, title })
+ })
})
diff --git a/components/anchor/__tests__/__snapshots__/demo.test.js.snap b/components/anchor/__tests__/__snapshots__/demo.test.js.snap
index 953443964..39f784438 100644
--- a/components/anchor/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/anchor/__tests__/__snapshots__/demo.test.js.snap
@@ -18,6 +18,20 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
`;
+exports[`renders ./components/anchor/demo/onClick.md correctly 1`] = `
+
+`;
+
exports[`renders ./components/anchor/demo/static.md correctly 1`] = `
diff --git a/components/anchor/demo/index.vue b/components/anchor/demo/index.vue
index 8dfe8c482..9b7fdd9af 100644
--- a/components/anchor/demo/index.vue
+++ b/components/anchor/demo/index.vue
@@ -1,6 +1,7 @@
+```
diff --git a/components/anchor/index.en-US.md b/components/anchor/index.en-US.md
index 9537f3589..017b9d55f 100644
--- a/components/anchor/index.en-US.md
+++ b/components/anchor/index.en-US.md
@@ -12,6 +12,11 @@
| offsetTop | Pixels to offset from top when calculating position of scroll | number | 0 |
| showInkInFixed | Whether show ink-balls in Fixed mode | boolean | false |
+### Events
+| Events Name | Description | Arguments |
+| --- | --- | --- |
+| click | set the handler to handle `click` event | Function(e: Event, link: Object) |
+
### Link Props
| Property | Description | Type | Default |
diff --git a/components/anchor/index.zh-CN.md b/components/anchor/index.zh-CN.md
index ac3a084f2..094cd5585 100644
--- a/components/anchor/index.zh-CN.md
+++ b/components/anchor/index.zh-CN.md
@@ -12,6 +12,11 @@
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | |
| showInkInFixed | 固定模式是否显示小圆点 | boolean | false |
+### 事件
+| 事件名称 | 说明 | 回调参数 |
+| --- | --- | --- |
+| click | `click` 事件的 handler | Function(e: Event, link: Object) |
+
### Link Props
| 成员 | 说明 | 类型 | 默认值 |
diff --git a/components/anchor/style/index.less b/components/anchor/style/index.less
index 235eb7815..3a5ddec9a 100644
--- a/components/anchor/style/index.less
+++ b/components/anchor/style/index.less
@@ -51,8 +51,8 @@
}
&-link {
- padding: 8px 0 8px 16px;
- line-height: 1;
+ padding: 7px 0 7px 16px;
+ line-height: 1.143;
&-title {
display: block;
@@ -62,7 +62,7 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- margin-bottom: 8px;
+ margin-bottom: 6px;
&:only-child {
margin-bottom: 0;
@@ -75,7 +75,7 @@
}
&-link &-link {
- padding-top: 6px;
- padding-bottom: 6px;
+ padding-top: 5px;
+ padding-bottom: 5px;
}
}
diff --git a/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap b/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap
index caad4b292..dc5a08f8e 100644
--- a/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap
@@ -10,7 +10,7 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
-
+
`;
@@ -23,10 +23,10 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
input here
-
+
@@ -41,7 +41,7 @@ exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
-
+
`;
@@ -56,7 +56,7 @@ exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly
-
+
`;
@@ -71,7 +71,7 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
-
+
`;
@@ -84,10 +84,10 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
input here
-
+
diff --git a/components/auto-complete/demo/index.vue b/components/auto-complete/demo/index.vue
index 8cf58f7e2..ab77ca2b2 100644
--- a/components/auto-complete/demo/index.vue
+++ b/components/auto-complete/demo/index.vue
@@ -18,13 +18,14 @@ const md = {
Autocomplete function of input field.
## When To Use
When there is a need for autocomplete functionality.
-## Examples
+## Examples
`,
}
export default {
category: 'Components',
subtitle: '自动完成',
type: 'Data Entry',
+ zhType: '数据录入',
cols: 2,
title: 'AutoComplete',
render () {
diff --git a/components/auto-complete/index.en-US.md b/components/auto-complete/index.en-US.md
index 87e8f74ef..8eb8d3a54 100644
--- a/components/auto-complete/index.en-US.md
+++ b/components/auto-complete/index.en-US.md
@@ -12,12 +12,14 @@
| slot="default" (for customize input element) | customize input element | HTMLInputElement / HTMLTextAreaElement | ` ` |
| dataSource | Data source for autocomplete | slot \| [DataSourceItemType](https://github.com/vueComponent/ant-design-vue/blob/724d53b907e577cf5880c1e6742d4c3f924f8f49/components/auto-complete/index.vue#L9)\[] | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true |
-| defaultValue | Initial selected option. | string\|string\[]\|{ key: string, label: string\|vNodes }\|Array<{ key: string, label: string\|vNodes }> | - |
+| defaultValue | Initial selected option. | string\|string\[]\| - |
| disabled | Whether disabled select | boolean | false |
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true |
| optionLabelProp | Which prop value of option will render as content of select. | string | `children` |
| placeholder | placeholder of input | string | - |
| value(v-model) | selected option | string\|string\[]\|{ key: string, label: string\|vNodes }\|Array<{ key: string, label: string\|vNodes }> | - |
+| defaultOpen | Initial open state of dropdown | boolean | - |
+| open | Controlled open state of dropdown | boolean | - |
### events
| Events Name | Description | Arguments |
@@ -27,6 +29,7 @@
| focus | Called when entering the component | function() |
| search | Called when searching items. | function(value) | - |
| select | Called when a option is selected. param is option's value and option instance. | function(value, option) |
+| dropdownVisibleChange | Call when dropdown open | function(open) |
## Methods
diff --git a/components/auto-complete/index.jsx b/components/auto-complete/index.jsx
index ad1e24224..d6e677569 100644
--- a/components/auto-complete/index.jsx
+++ b/components/auto-complete/index.jsx
@@ -122,9 +122,7 @@ const AutoComplete = {
},
class: cls,
ref: 'select',
- on: {
- ...$listeners,
- },
+ on: $listeners,
}
return (
` |
| dataSource | 自动完成的数据源 | slot \| [DataSourceItemType](https://github.com/vueComponent/ant-design-vue/blob/724d53b907e577cf5880c1e6742d4c3f924f8f49/components/auto-complete/index.vue#L9)\[] | |
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true |
-| defaultValue | 指定默认选中的条目 | string\|string\[]\|{ key: string, label: string\|vNodes }\|Array<{ key: string, label: string\|vNodes}> | 无 |
+| defaultValue | 指定默认选中的条目 | string\|string\[]\| 无 |
| disabled | 是否禁用 | boolean | false |
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true |
| optionLabelProp | 回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 `value`。 | string | `children` |
| placeholder | 输入框提示 | string \| slot | - |
| value(v-model) | 指定当前选中的条目 | string\|string\[]\|{ key: string, label: string\|vNodes }\|Array<{ key: string, label: string\|vNodes }> | 无 |
+| defaultOpen | 是否默认展开下拉菜单 | boolean | - |
+| open | 是否展开下拉菜单 | boolean | - |
### 事件
| 事件名称 | 说明 | 回调参数 |
@@ -27,6 +29,7 @@
| focus | 获得焦点时的回调 | function() |
| search | 搜索补全项的时候调用 | function(value) |
| select | 被选中时调用,参数为选中项的 value 值 | function(value, option) |
+| dropdownVisibleChange | 展开下拉菜单的回调 | function(open) |
## 方法
diff --git a/components/auto-complete/style/index.less b/components/auto-complete/style/index.less
index a8105799c..74e45c21c 100644
--- a/components/auto-complete/style/index.less
+++ b/components/auto-complete/style/index.less
@@ -52,6 +52,9 @@
&:hover {
.hover;
}
+ &[disabled] {
+ .disabled;
+ }
}
&-lg {
diff --git a/components/avatar/Avatar.jsx b/components/avatar/Avatar.jsx
index b150d0b58..5aedd58d8 100644
--- a/components/avatar/Avatar.jsx
+++ b/components/avatar/Avatar.jsx
@@ -110,13 +110,11 @@ export default {
} else {
const childrenNode = this.$refs.avatarChildren
if (childrenNode || (scale !== 1 && childrenNode)) {
+ const transformString = `scale(${scale}) translateX(-50%)`
const childrenStyle = {
- msTransform: `scale(${scale})`,
- WebkitTransform: `scale(${scale})`,
- transform: `scale(${scale})`,
- position: 'absolute',
- display: 'inline-block',
- left: `calc(50% - ${Math.round(childrenNode.offsetWidth / 2)}px)`,
+ msTransform: transformString,
+ WebkitTransform: transformString,
+ transform: transformString,
}
const sizeChildrenStyle = typeof size === 'number' ? {
lineHeight: `${size}px`,
diff --git a/components/avatar/__tests__/Avatar.test.js b/components/avatar/__tests__/Avatar.test.js
index 70e0e9f5c..c93fa6d5b 100644
--- a/components/avatar/__tests__/Avatar.test.js
+++ b/components/avatar/__tests__/Avatar.test.js
@@ -23,7 +23,7 @@ describe('Avatar Render', () => {
},
sync: false, attachToDocument: true,
})
- wrapper.vm.setScale = jest.fn(() => { wrapper.setData({ scale: 0.5 }) })
+ wrapper.vm.setScale = jest.fn(() => { wrapper.setData({ scale: 0.5 }); wrapper.vm.$forceUpdate() })
await asyncExpect(() => {
wrapper.find('img').trigger('error')
}, 0)
@@ -33,14 +33,10 @@ describe('Avatar Render', () => {
expect(children.at(0).text()).toBe('Fallback')
expect(wrapper.vm.setScale).toBeCalled()
})
- // await asyncExpect(() => {
- // console.log(wrapper.vm.scale, document.body.querySelector('.ant-avatar-string'))
- // expect(global.document.body.querySelector('.ant-avatar-string').style.transform).toBe('scale(0.5)')
- // global.document.body.innerHTML = ''
- // }, 1000)
await asyncExpect(() => {
-
- })
+ expect(global.document.body.querySelector('.ant-avatar-string').style.transform).toContain('scale(0.5)')
+ global.document.body.innerHTML = ''
+ }, 0)
})
it('should handle onError correctly', () => {
global.document.body.innerHTML = ''
diff --git a/components/avatar/__tests__/__snapshots__/demo.test.js.snap b/components/avatar/__tests__/__snapshots__/demo.test.js.snap
index aaea80bec..a6787108d 100644
--- a/components/avatar/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/avatar/__tests__/__snapshots__/demo.test.js.snap
@@ -1,14 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
`;
+exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
`;
exports[`renders ./components/avatar/demo/basic.md correctly 1`] = `
`;
exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `U 改 变
`;
-exports[`renders ./components/avatar/demo/type.md correctly 1`] = ` U USER U `;
+exports[`renders ./components/avatar/demo/type.md correctly 1`] = ` U USER U `;
diff --git a/components/avatar/demo/index.vue b/components/avatar/demo/index.vue
index 743c3ceba..9ae09de74 100644
--- a/components/avatar/demo/index.vue
+++ b/components/avatar/demo/index.vue
@@ -9,16 +9,20 @@ import US from '../index.en-US.md'
const md = {
cn: `# Avatar头像
用来代表用户或事物,支持图片、图标或字符展示。
+ ## 设计师专属
+安装 [Kitchen Sketch 插件 �](https://kitchen.alipay.com),一键填充高逼格头像和文本.
+
## 代码演示`,
us: `# Avatar
Avatars can be used to represent people or objects. It supports images, 'Icon's, or letters.
- ## Examples
+ ## Examples
`,
}
export default {
category: 'Components',
subtitle: '头像',
type: 'Data Display',
+ zhType: '数据展示',
title: 'Avatar',
render () {
return (
diff --git a/components/avatar/style/index.less b/components/avatar/style/index.less
index 9caf00959..da52c414d 100644
--- a/components/avatar/style/index.less
+++ b/components/avatar/style/index.less
@@ -49,6 +49,12 @@
line-height: @size;
}
+ &-string {
+ position: absolute;
+ left: 50%;
+ transform-origin: 0 center;
+ }
+
&.@{avatar-prefix-cls}-icon {
font-size: @font-size;
}
diff --git a/components/back-top/demo/index.vue b/components/back-top/demo/index.vue
index e6a93f968..eb9648fc5 100644
--- a/components/back-top/demo/index.vue
+++ b/components/back-top/demo/index.vue
@@ -21,6 +21,7 @@ const md = {
export default {
category: 'Components',
type: 'Other',
+ zhType: '其他',
subtitle: '回到顶部',
title: 'BackTop',
render () {
diff --git a/components/badge/Badge.jsx b/components/badge/Badge.jsx
index 258cd0b24..e9c9d5f25 100644
--- a/components/badge/Badge.jsx
+++ b/components/badge/Badge.jsx
@@ -73,7 +73,7 @@ export default {
[`${prefixCls}-not-a-wrapper`]: !children.length,
})
const styleWithOffset = offset ? {
- marginLeft: typeof offset[0] === 'number' ? `${offset[0]}px` : offset[0],
+ right: -parseInt(offset[0], 10),
marginTop: typeof offset[1] === 'number' ? `${offset[1]}px` : offset[1],
...numberStyle,
} : numberStyle
diff --git a/components/badge/__tests__/__snapshots__/demo.test.js.snap b/components/badge/__tests__/__snapshots__/demo.test.js.snap
index ba0f33ad4..6e4863e27 100644
--- a/components/badge/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/badge/__tests__/__snapshots__/demo.test.js.snap
@@ -5,13 +5,17 @@ exports[`renders ./components/badge/demo/basic.md correctly 1`] = `
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
-
+
-
+
`;
-exports[`renders ./components/badge/demo/dot.md correctly 1`] = ``;
+exports[`renders ./components/badge/demo/dot.md correctly 1`] = ``;
exports[`renders ./components/badge/demo/link.md correctly 1`] = `0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
`;
diff --git a/components/badge/demo/index.vue b/components/badge/demo/index.vue
index 25ba23d82..99d19c522 100644
--- a/components/badge/demo/index.vue
+++ b/components/badge/demo/index.vue
@@ -29,6 +29,7 @@
category: 'Components',
subtitle: '徽标数',
type: 'Data Display',
+ zhType: '数据展示',
title: 'Badge',
render () {
return (
@@ -61,6 +62,7 @@
border-radius: 4px;
background: #eee;
display: inline-block;
+ vertical-align: middle;
}
#components-badge-demo .ant-badge-not-a-wrapper:not(.ant-badge-status) {
margin-right: 8px;
diff --git a/components/badge/style/index.less b/components/badge/style/index.less
index 2de98e8d0..78616faa5 100644
--- a/components/badge/style/index.less
+++ b/components/badge/style/index.less
@@ -9,7 +9,6 @@
position: relative;
display: inline-block;
line-height: 1;
- vertical-align: middle;
color: unset;
&-count {
@@ -26,6 +25,7 @@
font-weight: @badge-font-weight;
white-space: nowrap;
box-shadow: 0 0 0 1px #fff;
+ z-index: 10;
a,
a:hover {
color: #fff;
@@ -81,7 +81,7 @@
height: 100%;
border-radius: 50%;
border: 1px solid @processing-color;
- content: '';
+ content: "";
animation: antStatusProcessing 1.2s infinite ease-in-out;
}
}
@@ -112,14 +112,18 @@
animation-fill-mode: both;
}
- &-not-a-wrapper .@{ant-prefix}-scroll-number {
- top: auto;
- display: block;
- position: relative;
- }
+ &-not-a-wrapper {
+ vertical-align: middle;
- &-not-a-wrapper .@{badge-prefix-cls}-count {
- transform: none;
+ .@{ant-prefix}-scroll-number {
+ top: auto;
+ display: block;
+ position: relative;
+ }
+
+ .@{badge-prefix-cls}-count {
+ transform: none;
+ }
}
}
diff --git a/components/breadcrumb/__tests__/__snapshots__/demo.test.js.snap b/components/breadcrumb/__tests__/__snapshots__/demo.test.js.snap
index daafe045e..211a16938 100644
--- a/components/breadcrumb/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/breadcrumb/__tests__/__snapshots__/demo.test.js.snap
@@ -12,7 +12,7 @@ exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
`;
exports[`renders ./components/breadcrumb/demo/withIcon.md correctly 1`] = `
-/ Application List /
+
`;
diff --git a/components/breadcrumb/demo/index.vue b/components/breadcrumb/demo/index.vue
index bbea90951..aec8c2f4a 100644
--- a/components/breadcrumb/demo/index.vue
+++ b/components/breadcrumb/demo/index.vue
@@ -31,6 +31,7 @@
category: 'Components',
subtitle: '面包屑',
type: 'Navigation',
+ zhType: '导航',
title: 'Breadcrumb',
render () {
return (
diff --git a/components/button/__tests__/__snapshots__/demo.test.js.snap b/components/button/__tests__/__snapshots__/demo.test.js.snap
index 3dab9dde4..4dff6fe2a 100644
--- a/components/button/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/button/__tests__/__snapshots__/demo.test.js.snap
@@ -11,10 +11,19 @@ exports[`renders ./components/button/demo/button-group.md correctly 1`] = `
L M R
L M M R
With Icon
- Go back
+
-
+ Go forward
+
+
+
`;
@@ -26,20 +35,60 @@ exports[`renders ./components/button/demo/disabled.md correctly 1`] = `
exports[`renders ./components/button/demo/ghost.md correctly 1`] = `Primary Default Dashed danger
`;
-exports[`renders ./components/button/demo/icon.md correctly 1`] = ` Search Search Search Search
`;
+exports[`renders ./components/button/demo/icon.md correctly 1`] = `
+
+
+
+
+ Search
+
+
+
+ Search
+
+
+
+ Search
+
+
+
+ Search
+`;
-exports[`renders ./components/button/demo/loading.md correctly 1`] = `Loading Loading mouseenter me! 延迟1s
`;
+exports[`renders ./components/button/demo/loading.md correctly 1`] = `
+
+
+ Loading
+
+ Loading mouseenter me!
+
+ 延迟1s
+
+
+
+
+`;
exports[`renders ./components/button/demo/multiple.md correctly 1`] = `
Primary secondary
- Actions
+ Actions
+
+
`;
exports[`renders ./components/button/demo/size.md correctly 1`] = `
`;
diff --git a/components/button/__tests__/__snapshots__/index.test.js.snap b/components/button/__tests__/__snapshots__/index.test.js.snap
index 0a9dc15e2..834e92354 100644
--- a/components/button/__tests__/__snapshots__/index.test.js.snap
+++ b/components/button/__tests__/__snapshots__/index.test.js.snap
@@ -6,15 +6,35 @@ exports[`Button fixbug renders {0} , 0 and {false} 2`] = ` `;
-exports[`Button renders Chinese characters correctly 1`] = `按钮 `;
+exports[`Button renders Chinese characters correctly 1`] = `
+
+
+ 按钮
+`;
-exports[`Button renders Chinese characters correctly 2`] = ` 按钮 `;
+exports[`Button renders Chinese characters correctly 2`] = `
+
+
+ 按钮
+`;
-exports[`Button renders Chinese characters correctly 3`] = `按钮 `;
+exports[`Button renders Chinese characters correctly 3`] = `
+
+
+ 按钮
+`;
-exports[`Button renders Chinese characters correctly 4`] = `按钮 `;
+exports[`Button renders Chinese characters correctly 4`] = `
+
+
+ 按钮
+`;
-exports[`Button renders Chinese characters correctly 5`] = `按 钮 `;
+exports[`Button renders Chinese characters correctly 5`] = `
+
+
+ 按 钮
+`;
exports[`Button renders correctly 1`] = `Follow `;
diff --git a/components/button/button.jsx b/components/button/button.jsx
index 7a49ebffa..36a21e8fb 100644
--- a/components/button/button.jsx
+++ b/components/button/button.jsx
@@ -65,7 +65,10 @@ export default {
methods: {
fixTwoCNChar () {
// Fix for HOC usage like
- const node = this.$el
+ const node = this.$refs.buttonNode
+ if (!node) {
+ return
+ }
const buttonText = node.textContent || node.innerText
if (this.isNeedInserted() && isTwoCNChar(buttonText)) {
if (!this.hasTwoCNChar) {
@@ -76,9 +79,10 @@ export default {
}
},
handleClick (event) {
- // this.clicked = true
- // clearTimeout(this.timeout)
- // this.timeout = setTimeout(() => (this.clicked = false), 500)
+ const { sLoading } = this.$data
+ if (sLoading) {
+ return
+ }
this.$emit('click', event)
},
insertSpace (child, needInserted) {
@@ -101,6 +105,9 @@ export default {
const { htmlType, classes, icon,
disabled, handleClick,
sLoading, $slots, $attrs, $listeners } = this
+ const now = new Date()
+ const isChristmas = now.getMonth() === 11 && now.getDate() === 25
+ const title = isChristmas ? 'Ho Ho Ho!' : $attrs.title
const buttonProps = {
props: {
},
@@ -108,8 +115,9 @@ export default {
...$attrs,
type: htmlType,
disabled,
+ title,
},
- class: classes,
+ class: { ...classes, christmas: isChristmas },
on: {
...$listeners,
click: handleClick,
@@ -118,16 +126,17 @@ export default {
const iconType = sLoading ? 'loading' : icon
const iconNode = iconType ? : null
const kids = $slots.default && $slots.default.length === 1 ? this.insertSpace($slots.default[0], this.isNeedInserted()) : $slots.default
+
if ('href' in $attrs) {
return (
-
+
{iconNode}{kids}
)
} else {
return (
-
+
{iconNode}{kids}
diff --git a/components/button/demo/index.vue b/components/button/demo/index.vue
index a39748f17..29c380c90 100644
--- a/components/button/demo/index.vue
+++ b/components/button/demo/index.vue
@@ -26,6 +26,7 @@ const md = {
export default {
category: 'Components',
type: 'General',
+ zhType: '通用',
title: 'Button',
subtitle: '按钮',
render () {
diff --git a/components/button/index.en-US.md b/components/button/index.en-US.md
index 01844a0d4..9c3ea1361 100644
--- a/components/button/index.en-US.md
+++ b/components/button/index.en-US.md
@@ -17,7 +17,7 @@ To get a customized button, just set `type`/`shape`/`size`/`loading`/`disabled`.
### events
| Events Name | Description | Arguments |
| --- | --- | --- |
-| click | set the handler to handle `click` event | function(e) |
+| click | set the handler to handle `click` event | (event) => void |
`Hello world! ` will be rendered into `Hello world! `, and all the properties which are not listed above will be transferred to the `` tag.
diff --git a/components/button/index.zh-CN.md b/components/button/index.zh-CN.md
index 80971eafc..afd88a3a8 100644
--- a/components/button/index.zh-CN.md
+++ b/components/button/index.zh-CN.md
@@ -19,7 +19,7 @@
### 事件
| 事件名称 | 说明 | 回调参数 |
| --- | --- | --- |
-| click | `click` 事件的 handler | function(e) |
+| click | 点击按钮时的回调 | (event) => void |
-`Hello world! ` 最终会被渲染为 `Hello world! `,并且除了上表中的属性,其它属性都会直接传到 ` `。
+`Hello world! ` 最终会被渲染为 `Hello world! `,并且除了上表中的属性,其它属性都会直接传到原生 button 上。
diff --git a/components/button/style/index.less b/components/button/style/index.less
index d0029d7af..fee28d969 100644
--- a/components/button/style/index.less
+++ b/components/button/style/index.less
@@ -12,7 +12,10 @@
// Button styles
// -----------------------------
.@{btn-prefix-cls} {
- line-height: @line-height-base;
+ // Fixing https://github.com/ant-design/ant-design/issues/12978
+ // It is a render problem of chrome, which is only happened in the codesandbox demo
+ // 0.001px solution works and I don't why
+ line-height: @line-height-base - 0.001;
.btn;
.btn-default;
@@ -21,6 +24,7 @@
> i,
> span {
pointer-events: none;
+ display: inline-block;
}
&-primary {
@@ -78,7 +82,7 @@
right: -1px;
background: #fff;
opacity: 0.35;
- content: '';
+ content: "";
border-radius: inherit;
z-index: 1;
transition: opacity .2s;
@@ -149,7 +153,7 @@
letter-spacing: .34em;
}
- &-two-chinese-chars > * {
+ &-two-chinese-chars > *:not(.@{iconfont-css-prefix}) {
letter-spacing: .34em;
margin-right: -.34em;
}
@@ -157,6 +161,31 @@
&-block {
width: 100%;
}
+
+ .christmas&-primary:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: -6px;
+ left: 0;
+ right: 0;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAXCAYAAABOHMIhAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABiZJREFUeNrsWMtPlFcUvzPMwIDysLyRR4uATDHWCiVgSmRlios2DeiiXUFs0nRBd6arxqQhJDapkYXhP4BqDKTQhZaFNQSCaBEVJjwdHsNr5DUMDDPDzPT3u7nTDEgRKrKgc5KT+z3uufec33de99P4fD4RpL2RNgjB3kn35MkTeRERESFiYmLkGBoaKnQ6nWSNRvPPZFxr+vv7k6KioiIdDsfa8vLyQkFBgcP3Bnel3MDAQArWI0eFhISE87nb7bZ7PJ4VvLYuLi5O5+fnu9+kMNfq6+tLjIyMzMY6KeBEbK/XarXReI3lPDZMWcc4v7GxYV1dXR3Jy8ub2E5HPvJ6vRSSDH0ku1wuAfsEZOV1IEFHoeNFdHS0yMrK2knR0Lm5uR+hxLdQMjbwHTZbB41h8RGwCdc9MzMzneHh4bGJiYlf4SN8ijkfwqiIncCAAR7Iz2GPSShudjqdfeCeqampvwBQfFxc3JdYqwTv8gB8/F48A8BgKecE14V+L7ju2tpae05OzkuCCZvkPOj8mizmC6vVKtmPu+bx48cC3qI1mUyFUOyywWD4SHlELBaLJmCHNcwAghuAOujtuF4FqHO4nsX4EsAS3I4TJ04ME1h8PDE9PS09TYZoY2Pj1729vd6lpSVfkDYTPG0UkfNDRUWFgQ5Gb2Mh0N29e9eG/GQfHh4W8/PzwUy/ObQ/gMfVVlZW1iAiZdQxp3nv3LljRoL/5erVq1UIxzSiiVD9X4EDYATynCwAzGO858hCQRoaGmJFZNJz8YIcBc4BF966dau6sLAwBxVSJCUlCSThQwuU3W6XkYUok1Vzm5znQx5bbm9v77p+/frPeNSNRzZ/ISBwrG4ZR48eLamtrf2+uLjYSEG9Xi/wTISFhQlWGXohyzO/CJlVl23KQRLbABoaHx+/Z1lUZ/Hq1SsJFj3JT3hmHx8fnydPTEzMj46OziHPW2w22wxeD4Kfgadh/4YEzU8Az4DhffAn5eXlX1y6dKkEoCTspAQ9Mjs7+0BBo8Fms1lkZGTsOo0QLLRNkvnR+fEJzIMHD0xtbW39CL8JTFtSbAOvBIyLHIGVm9VzE2gKuDAMSSpcT6KXyT137lx2cnLyMXhcGDb3wq3XuWF3d/fCzZs3P0c4v5eSknJQbYLo7Ox0gC2lpaVZ3Be67Th/dnZWoAJKsJC3XA8fPhxoamp6hMb+BaaMgWcUMGtszZjiFDNmvcDI91pzG0iY4ARwkwrxkcHBwUdgNrRMbnrqoRbkVzDcvn3bl5qaWsmcgFH4G8XdEGUWFhak51AuISFBnkoCTyFbyWKxCJwIxlC0fq2rq7tcVFRkRKskjh8/Lr0+kBjCCDV/knfdv3//WX19/R8IRRNemxlu4AXwKqM+EJwdj1HbPYSwh3sCPAJDABm2LLchCjS+5/kirKGhwWk0GrMuXrxYQuX9hm/XXTMXMY+srKwI5ApZrbYmZh7deEJhAUKjLe/pLTzSsCuHrK+1tbUJVe3P6upq87Vr174rKysrYHVj/uW+OH3IfEuw4F3ee/fuPQfAvwOs5yyE4CnlFOu7BWrTCWlreO6FACpBZGwUw4BvkANLobReHb3kGZYGsGzTq/zlO8AT1ru6uoZbWlqeA6gINJAfnz59OlVLoX8Jtebm5raampqfcMvQYgTknz9//sKVK1c+y83NTdIEuCnaKMuNGzd+6+np6cCtSTkAw9D9X8Dyh+dbgaaAC1XAnUlPTy+qqqq6cPbs2UzkmWjNljiDJzpwHFnCkW2yo6NjCKW8H54wjlezKvRT09LSTsJrz5w6dSoN+Yp51ADAPUj8VoDbDq9pxrwuJcNIYQllJTIi/xopBw/VA7DJp0+f9hA78CgL5F5C8J2CpoCj8sfA6WCe/FPRhsRlZmbGIs8Y4FFO5CJgtrSsvrRVGW1V93b1myoGnKAKEcHgnwsWpg1lNI0fphwrmdqbckeU18WrnlOjqp5/j7W3BWvfQVPKa5SBkcrYCNVB65TRTlWZ1lXiXVU5xbtlDb2SPaLWYwrgHIcqPg6Vc7fbX69Yoyqfa7/AeiegbWOEVhmsVcWDwPn224iDJgla8Hd38Hd3ELQgaIeI/hZgAIPEp0vmQJdoAAAAAElFTkSuQmCC) no-repeat 50% 0;
+ background-size: 64px;
+ opacity: 1;
+ }
+
+ .christmas&-primary&-lg:before {
+ background-size: 72px;
+ }
+
+ .christmas&-primary&-sm:before {
+ background-size: 56px;
+ }
+
+ // https://github.com/ant-design/ant-design/issues/12681
+ &:empty {
+ vertical-align: top;
+ }
}
a.@{btn-prefix-cls} {
diff --git a/components/button/style/mixin.less b/components/button/style/mixin.less
index 699aa8646..138ca4903 100644
--- a/components/button/style/mixin.less
+++ b/components/button/style/mixin.less
@@ -16,12 +16,17 @@
&:active,
&.active {
.button-color(@btn-disable-color; @btn-disable-bg; @btn-disable-border);
+ text-shadow: none;
+ box-shadow: none;
}
}
}
.button-variant-primary(@color; @background) {
.button-color(@color; @background; @background);
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .12);
+ box-shadow: 0 2px 0 rgba(0, 0, 0, .045);
+
&:hover,
&:focus {
.button-color(@color; ~`colorPalette("@{background}", 5)`; ~`colorPalette("@{background}", 5)`);
@@ -72,6 +77,7 @@
.button-variant-ghost(@color) {
.button-color(@color; transparent; @color);
+ text-shadow: none;
&:hover,
&:focus {
@@ -95,7 +101,7 @@
> a:only-child {
color: currentColor;
&:after {
- content: '';
+ content: "";
position: absolute;
top: 0;
left: 0;
@@ -112,7 +118,6 @@
> .@{btnClassName},
> span > .@{btnClassName} {
position: relative;
- line-height: @btn-height-base - 2px;
&:hover,
&:focus,
@@ -158,6 +163,7 @@
user-select: none;
transition: all .3s @ease-in-out;
position: relative;
+ box-shadow: 0 2px 0 rgba(0, 0, 0, .015);
> .@{iconfont-css-prefix} {
line-height: 1;
@@ -175,7 +181,7 @@
&:not([disabled]):active {
outline: 0;
- transition: none;
+ box-shadow: none;
}
&.disabled,
diff --git a/components/calendar/Header.jsx b/components/calendar/Header.jsx
index 43da7f308..bf0442c0b 100644
--- a/components/calendar/Header.jsx
+++ b/components/calendar/Header.jsx
@@ -84,7 +84,7 @@ export default {
const currentYear = value.get('year')
if (rangeEnd.get('year') === currentYear) {
end = rangeEnd.get('month') + 1
- } else {
+ } else if (rangeStart.get('year') === currentYear) {
start = rangeStart.get('month')
}
}
diff --git a/components/calendar/__tests__/__snapshots__/demo.test.js.snap b/components/calendar/__tests__/__snapshots__/demo.test.js.snap
index e48c4e450..00db10164 100644
--- a/components/calendar/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/calendar/__tests__/__snapshots__/demo.test.js.snap
@@ -7,14 +7,14 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
Month Year
@@ -313,14 +313,14 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
Month Year
@@ -619,14 +619,14 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
Month Year
@@ -1032,14 +1032,14 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
Month Year
@@ -1336,14 +1336,14 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
Month Year
diff --git a/components/calendar/__tests__/__snapshots__/index.test.js.snap b/components/calendar/__tests__/__snapshots__/index.test.js.snap
new file mode 100644
index 000000000..6f1ea3eb1
--- /dev/null
+++ b/components/calendar/__tests__/__snapshots__/index.test.js.snap
@@ -0,0 +1,306 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Calendar Calendar should support locale 1`] = `
+
+
+
+
+
+
+
+ Su
+ Mo
+ Tu
+ We
+ Th
+ Fr
+ Sa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/components/calendar/__tests__/index.test.js b/components/calendar/__tests__/index.test.js
index be4cee1ac..2ec381db6 100644
--- a/components/calendar/__tests__/index.test.js
+++ b/components/calendar/__tests__/index.test.js
@@ -1,14 +1,14 @@
import Moment from 'moment'
import { mount } from '@vue/test-utils'
import { asyncExpect } from '@/tests/utils'
-import Vue from 'vue'
+import MockDate from 'mockdate'
import Calendar from '..'
function $$ (className) {
return document.body.querySelectorAll(className)
}
describe('Calendar', () => {
- it('Calendar should be selectable', () => {
+ it('Calendar should be selectable', async () => {
const onSelect = jest.fn()
const wrapper = mount(
{
@@ -18,13 +18,17 @@ describe('Calendar', () => {
},
{ sync: false }
)
- wrapper.findAll('.ant-fullcalendar-cell').at(0).trigger('click')
- expect(onSelect).toBeCalledWith(expect.anything())
- const value = onSelect.mock.calls[0][0]
- expect(Moment.isMoment(value)).toBe(true)
+ await asyncExpect(() => {
+ wrapper.findAll('.ant-fullcalendar-cell').at(0).trigger('click')
+ })
+ await asyncExpect(() => {
+ expect(onSelect).toBeCalledWith(expect.anything())
+ const value = onSelect.mock.calls[0][0]
+ expect(Moment.isMoment(value)).toBe(true)
+ })
})
- it('only Valid range should be selectable', () => {
+ it('only Valid range should be selectable', async () => {
const onSelect = jest.fn()
const validRange = [Moment('2018-02-02'), Moment('2018-02-18')]
const wrapper = mount(
@@ -35,12 +39,14 @@ describe('Calendar', () => {
},
{ sync: false }
)
- wrapper.findAll('[title="February 1, 2018"]').at(0).trigger('click')
- wrapper.findAll('[title="February 2, 2018"]').at(0).trigger('click')
- expect(onSelect.mock.calls.length).toBe(1)
+ await asyncExpect(() => {
+ wrapper.findAll('[title="February 1, 2018"]').at(0).trigger('click')
+ wrapper.findAll('[title="February 2, 2018"]').at(0).trigger('click')
+ expect(onSelect.mock.calls.length).toBe(1)
+ })
})
- it('dates other than in valid range should be disabled', () => {
+ it('dates other than in valid range should be disabled', async () => {
const onSelect = jest.fn()
const validRange = [Moment('2018-02-02'), Moment('2018-02-18')]
const wrapper = mount(
@@ -51,12 +57,14 @@ describe('Calendar', () => {
},
{ sync: false }
)
- wrapper.findAll('[title="February 20, 2018"]').at(0).trigger('click')
- expect(wrapper.find('[title="February 20, 2018"]').classes()).toContain('ant-fullcalendar-disabled-cell')
- expect(onSelect.mock.calls.length).toBe(0)
+ await asyncExpect(() => {
+ wrapper.findAll('[title="February 20, 2018"]').at(0).trigger('click')
+ expect(wrapper.find('[title="February 20, 2018"]').classes()).toContain('ant-fullcalendar-disabled-cell')
+ expect(onSelect.mock.calls.length).toBe(0)
+ })
})
- it('months other than in valid range should be disabled', () => {
+ it('months other than in valid range should be disabled', async () => {
const onSelect = jest.fn()
const validRange = [Moment('2018-02-02'), Moment('2018-05-18')]
const wrapper = mount(
@@ -67,12 +75,14 @@ describe('Calendar', () => {
},
{ sync: false }
)
- expect(wrapper.findAll('[title="Jan"]').at(0).classes()).toContain('ant-fullcalendar-month-panel-cell-disabled')
- expect(wrapper.findAll('[title="Feb"]').at(0).classes()).not.toContain('ant-fullcalendar-month-panel-cell-disabled')
- expect(wrapper.findAll('[title="Jun"]').at(0).classes()).toContain('ant-fullcalendar-month-panel-cell-disabled')
- wrapper.findAll('[title="Jan"]').at(0).trigger('click')
- wrapper.findAll('[title="Mar"]').at(0).trigger('click')
- expect(onSelect.mock.calls.length).toBe(1)
+ await asyncExpect(() => {
+ expect(wrapper.findAll('[title="Jan"]').at(0).classes()).toContain('ant-fullcalendar-month-panel-cell-disabled')
+ expect(wrapper.findAll('[title="Feb"]').at(0).classes()).not.toContain('ant-fullcalendar-month-panel-cell-disabled')
+ expect(wrapper.findAll('[title="Jun"]').at(0).classes()).toContain('ant-fullcalendar-month-panel-cell-disabled')
+ wrapper.findAll('[title="Jan"]').at(0).trigger('click')
+ wrapper.findAll('[title="Mar"]').at(0).trigger('click')
+ expect(onSelect.mock.calls.length).toBe(1)
+ })
})
it('months other than in valid range should not be shown in header', async () => {
@@ -92,15 +102,9 @@ describe('Calendar', () => {
await asyncExpect(() => {
$$('.ant-select-dropdown-menu-item')[0].click()
}, 0)
- // await asyncExpect(() => {
- // wrapper.find('.ant-fullcalendar-month-select').trigger('click')
- // })
- // await asyncExpect(() => {
- // expect($$('.ant-select-dropdown-menu-item').length).toBe(13)
- // })
})
- it('getDateRange should returns a disabledDate function', () => {
+ it('getDateRange should returns a disabledDate function', async () => {
const validRange = [Moment('2018-02-02'), Moment('2018-05-18')]
const wrapper = mount(
Calendar, {
@@ -111,25 +115,28 @@ describe('Calendar', () => {
sync: false,
}
)
- const instance = wrapper.vm
- const disabledDate = instance.getDateRange(validRange)
- expect(disabledDate(Moment('2018-06-02'))).toBe(true)
- expect(disabledDate(Moment('2018-04-02'))).toBe(false)
- })
-
- it('Calendar should change mode by prop', (done) => {
- const monthMode = 'month'
- const yearMode = 'year'
- const wrapper = mount(Calendar, { sync: false })
- expect(wrapper.vm.sMode).toEqual(monthMode)
- wrapper.setProps({ mode: 'year' })
- Vue.nextTick(() => {
- expect(wrapper.vm.sMode).toEqual(yearMode)
- done()
+ await asyncExpect(() => {
+ const instance = wrapper.vm
+ const disabledDate = instance.getDateRange(validRange)
+ expect(disabledDate(Moment('2018-06-02'))).toBe(true)
+ expect(disabledDate(Moment('2018-04-02'))).toBe(false)
})
})
- it('Calendar should switch mode', (done) => {
+ it('Calendar should change mode by prop', async () => {
+ const monthMode = 'month'
+ const yearMode = 'year'
+ const wrapper = mount(Calendar, { sync: false })
+ await asyncExpect(() => {
+ expect(wrapper.vm.sMode).toEqual(monthMode)
+ wrapper.setProps({ mode: 'year' })
+ })
+ await asyncExpect(() => {
+ expect(wrapper.vm.sMode).toEqual(yearMode)
+ })
+ })
+
+ it('Calendar should switch mode', async () => {
const monthMode = 'month'
const yearMode = 'year'
const onPanelChangeStub = jest.fn()
@@ -144,12 +151,26 @@ describe('Calendar', () => {
sync: false,
}
)
- expect(wrapper.vm.sMode).toEqual(yearMode)
- wrapper.vm.setType('date')
- Vue.nextTick(() => {
+ await asyncExpect(() => {
+ expect(wrapper.vm.sMode).toEqual(yearMode)
+ wrapper.vm.setType('date')
+ })
+ await asyncExpect(() => {
expect(wrapper.vm.sMode).toEqual(monthMode)
expect(onPanelChangeStub).toHaveBeenCalledTimes(1)
- done()
+ })
+ })
+
+ it('Calendar should support locale', async () => {
+ MockDate.set(Moment('2018-10-19'))
+ // eslint-disable-next-line
+ const zhCN = require('../locale/zh_CN').default;
+ const wrapper = mount(Calendar, { propsData: {
+ locale: zhCN,
+ }, sync: false })
+ await asyncExpect(() => {
+ expect(wrapper.html()).toMatchSnapshot()
+ MockDate.reset()
})
})
})
diff --git a/components/calendar/demo/index.vue b/components/calendar/demo/index.vue
index 9be0423c9..f81368e01 100644
--- a/components/calendar/demo/index.vue
+++ b/components/calendar/demo/index.vue
@@ -28,6 +28,7 @@ When data is in the form of dates, such as schedules, timetables, prices calenda
export default {
category: 'Components',
type: 'Data Display',
+ zhType: '数据展示',
subtitle: '日历',
cols: 1,
title: 'Calendar',
diff --git a/components/calendar/index.en-US.md b/components/calendar/index.en-US.md
index c248c7404..7763009f8 100644
--- a/components/calendar/index.en-US.md
+++ b/components/calendar/index.en-US.md
@@ -4,7 +4,7 @@
**Note:** Part of the Calendar's locale is read from `value`. So, please set the locale of `moment` correctly.
````html
-// The default locale is en-US, if you want to use other locale, just set locale in entry file globaly.
+// The default locale is en-US, if you want to use other locale, just set locale in entry file globally.
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
diff --git a/components/calendar/index.jsx b/components/calendar/index.jsx
index f21e0f257..891df3a1e 100644
--- a/components/calendar/index.jsx
+++ b/components/calendar/index.jsx
@@ -41,7 +41,7 @@ export const CalendarProps = () => ({
// monthCellRender: PropTypes.func,
// dateFullCellRender: PropTypes.func,
// monthFullCellRender: PropTypes.func,
- locale: PropTypes.any,
+ locale: PropTypes.object,
// onPanelChange?: (date?: moment.Moment, mode?: CalendarMode) => void;
// onSelect?: (date?: moment.Moment) => void;
disabledDate: PropTypes.func,
@@ -226,13 +226,24 @@ const Calendar = {
)
},
+ getDefaultLocale () {
+ const result = {
+ ...enUS,
+ ...this.$props.locale,
+ }
+ result.lang = {
+ ...result.lang,
+ ...(this.$props.locale || {}).lang,
+ }
+ return result
+ },
},
render () {
return (
`;
-exports[`renders ./components/card/demo/concise.md correctly 1`] = `
-
-
-
Card content
-
Card content
-
Card content
-
-
-`;
-
exports[`renders ./components/card/demo/flexible-content.md correctly 1`] = `
@@ -236,9 +226,9 @@ exports[`renders ./components/card/demo/meta.md correctly 1`] = `
`;
@@ -262,13 +252,13 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = `
-
-
+
+
@@ -292,8 +287,8 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = `
-
-
+
+
diff --git a/components/card/__tests__/__snapshots__/index.test.js.snap b/components/card/__tests__/__snapshots__/index.test.js.snap
index 3bf46ab53..7c2b47bf3 100644
--- a/components/card/__tests__/__snapshots__/index.test.js.snap
+++ b/components/card/__tests__/__snapshots__/index.test.js.snap
@@ -59,3 +59,17 @@ exports[`Card should still have padding when card which set padding to 0 is load
`;
+
+exports[`Card title should be vertically aligned 1`] = `
+
+`;
diff --git a/components/card/__tests__/index.test.js b/components/card/__tests__/index.test.js
index b1acbcc03..01a6ad63c 100644
--- a/components/card/__tests__/index.test.js
+++ b/components/card/__tests__/index.test.js
@@ -1,5 +1,6 @@
import { mount } from '@vue/test-utils'
import Card from '../index'
+import Button from '../../button/index'
const testMethod = typeof window !== 'undefined' ? it : xit
@@ -46,4 +47,15 @@ describe('Card', () => {
})
expect(wrapper.html()).toMatchSnapshot()
})
+
+ it('title should be vertically aligned', () => {
+ const wrapper = mount({
+ render () {
+ return
Button} style={{ width: '300px' }}>
+ Card content
+
+ },
+ })
+ expect(wrapper.html()).toMatchSnapshot()
+ })
})
diff --git a/components/card/demo/concise.md b/components/card/demo/concise.md
deleted file mode 100644
index 0ee3c79d7..000000000
--- a/components/card/demo/concise.md
+++ /dev/null
@@ -1,19 +0,0 @@
-
- #### 简洁卡片
- 只包含内容区域
-
-
-
- #### Simple card
- A simple card only containing a content area.
-
-
-```html
-
-
- Card content
- Card content
- Card content
-
-
-```
diff --git a/components/card/demo/index.vue b/components/card/demo/index.vue
index 541dcb930..41d6f55ea 100644
--- a/components/card/demo/index.vue
+++ b/components/card/demo/index.vue
@@ -1,7 +1,6 @@
+```
+
diff --git a/components/cascader/index.en-US.md b/components/cascader/index.en-US.md
index a8376f6d0..386438080 100644
--- a/components/cascader/index.en-US.md
+++ b/components/cascader/index.en-US.md
@@ -26,6 +26,7 @@
| popupVisible | set visible of cascader popup | boolean | - |
| showSearch | Whether show search input in single mode. | boolean\|object | false |
| size | input size, one of `large` `default` `small` | string | `default` |
+| suffixIcon | The custom suffix icon | string \| VNode \| slot | - |
| value(v-model) | selected value | string\[] | - |
Fields in `showSearch`:
diff --git a/components/cascader/index.jsx b/components/cascader/index.jsx
index 691a31913..9c7620c40 100644
--- a/components/cascader/index.jsx
+++ b/components/cascader/index.jsx
@@ -7,8 +7,9 @@ import omit from 'omit.js'
import KeyCode from '../_util/KeyCode'
import Input from '../input'
import Icon from '../icon'
-import { hasProp, filterEmpty, getOptionProps, getStyle, getClass, getAttrs } from '../_util/props-util'
+import { hasProp, filterEmpty, getOptionProps, getStyle, getClass, getAttrs, getComponentFromProp, isValidElement } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
+import { cloneElement } from '../_util/vnode'
const CascaderOptionType = PropTypes.shape({
value: PropTypes.string,
@@ -74,6 +75,7 @@ const CascaderProps = {
popupVisible: PropTypes.bool,
fieldNames: FieldNamesType,
autoFocus: PropTypes.bool,
+ suffixIcon: PropTypes.any,
}
function defaultFilterOption (inputValue, path, names) {
@@ -88,7 +90,7 @@ function defaultSortFilteredOption (a, b, inputValue, names) {
return a.findIndex(callback) - b.findIndex(callback)
}
-function getFilledFieldNames (fieldNames = {}) {
+function getFilledFieldNames ({ fieldNames = {}}) {
const names = {
children: fieldNames.children || 'children',
label: fieldNames.label || 'label',
@@ -110,13 +112,13 @@ const Cascader = {
},
data () {
this.cachedOptions = []
- const { value, defaultValue, popupVisible, showSearch, options, changeOnSelect, flattenTree, fieldNames } = this
+ const { value, defaultValue, popupVisible, showSearch, options, flattenTree } = this
return {
sValue: value || defaultValue || [],
inputValue: '',
inputFocused: false,
sPopupVisible: popupVisible,
- flattenOptions: showSearch ? flattenTree(options, changeOnSelect, fieldNames) : undefined,
+ flattenOptions: showSearch ? flattenTree(options, this.$props) : undefined,
}
},
mounted () {
@@ -135,7 +137,7 @@ const Cascader = {
},
options (val) {
if (this.showSearch) {
- this.setState({ flattenOptions: this.flattenTree(this.options, this.changeOnSelect, this.fieldNames) })
+ this.setState({ flattenOptions: this.flattenTree(this.options, this.$props) })
}
},
},
@@ -218,8 +220,8 @@ const Cascader = {
},
getLabel () {
- const { options, $scopedSlots, fieldNames } = this
- const names = getFilledFieldNames(fieldNames)
+ const { options, $scopedSlots } = this
+ const names = getFilledFieldNames(this.$props)
const displayRender = this.displayRender || $scopedSlots.displayRender || defaultDisplayRender
const value = this.sValue
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value
@@ -242,18 +244,18 @@ const Cascader = {
}
},
- flattenTree (options, changeOnSelect, fieldNames, ancestor = []) {
- const names = getFilledFieldNames(fieldNames)
+ flattenTree (options, props, ancestor = []) {
+ const names = getFilledFieldNames(props)
let flattenOptions = []
const childrenName = names.children
options.forEach((option) => {
const path = ancestor.concat(option)
- if (changeOnSelect || !option[childrenName] || !option[childrenName].length) {
+ if (props.changeOnSelect || !option[childrenName] || !option[childrenName].length) {
flattenOptions.push(path)
}
if (option[childrenName]) {
flattenOptions = flattenOptions.concat(
- this.flattenTree(option[childrenName], changeOnSelect, fieldNames, path)
+ this.flattenTree(option[childrenName], props, path)
)
}
})
@@ -261,8 +263,8 @@ const Cascader = {
},
generateFilteredOptions (prefixCls) {
- const { showSearch, notFoundContent, $scopedSlots, fieldNames } = this
- const names = getFilledFieldNames(fieldNames)
+ const { showSearch, notFoundContent, $scopedSlots } = this
+ const names = getFilledFieldNames(this.$props)
const {
filter = defaultFilterOption,
// render = this.defaultRenderFilteredOption,
@@ -308,6 +310,8 @@ const Cascader = {
const { $slots, sPopupVisible, inputValue, $listeners } = this
const { sValue: value, inputFocused } = this.$data
const props = getOptionProps(this)
+ let suffixIcon = getComponentFromProp(this, 'suffixIcon')
+ suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon
const {
prefixCls, inputPrefixCls, placeholder, size, disabled,
allowClear, showSearch = false, ...otherProps } = props
@@ -318,7 +322,8 @@ const Cascader = {
})
const clearIcon = (allowClear && !disabled && value.length > 0) || inputValue ? (
{suffixIcon}) || (
+
+ )
+
const input = children.length ? children : (
: null}
{clearIcon}
-
+ {inputIcon}
+
+ )
+
+ const expandIcon = (
+
+ )
+
+ const loadingIcon = (
+
)
const cascaderProps = {
@@ -427,6 +455,8 @@ const Cascader = {
value: value,
popupVisible: sPopupVisible,
dropdownMenuColumnStyle: dropdownMenuColumnStyle,
+ expandIcon,
+ loadingIcon,
},
on: {
...$listeners,
diff --git a/components/cascader/index.zh-CN.md b/components/cascader/index.zh-CN.md
index aad91e236..1a0d58d17 100644
--- a/components/cascader/index.zh-CN.md
+++ b/components/cascader/index.zh-CN.md
@@ -26,6 +26,7 @@
| popupVisible | 控制浮层显隐 | boolean | - |
| showSearch | 在选择框中显示搜索框 | boolean | false |
| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
+| suffixIcon | 自定义的选择框后缀图标 | string \| VNode \| slot | - |
| value(v-model) | 指定选中项 | string\[] | - |
`showSearch` 为对象时,其中的字段:
diff --git a/components/cascader/style/index.less b/components/cascader/style/index.less
index 29a33593a..5de52826e 100644
--- a/components/cascader/style/index.less
+++ b/components/cascader/style/index.less
@@ -13,7 +13,7 @@
background-color: transparent !important;
cursor: pointer;
width: 100%;
- position: static;
+ position: relative;
}
&-picker-show-search &-input.@{ant-prefix}-input {
@@ -101,13 +101,9 @@
margin-top: -6px;
line-height: 12px;
color: @disabled-color;
- &:before {
- transition: transform .2s;
- }
+ transition: transform .2s;
&&-expand {
- &:before {
- transform: rotate(180deg);
- }
+ transform: rotate(180deg);
}
}
}
@@ -205,17 +201,14 @@
&-expand {
position: relative;
padding-right: 24px;
- &:after {
- .iconfont-font("\e61f");
- .iconfont-size-under-12px(8px);
- color: @text-color-secondary;
- position: absolute;
- right: @control-padding-horizontal;
- }
}
- &-loading:after {
- .iconfont-font("\e64d");
- animation: loadingCircle 1s infinite linear;
+
+ &-expand &-expand-icon,
+ &-expand &-loading-icon {
+ .iconfont-size-under-12px(10px);
+ color: @text-color-secondary;
+ position: absolute;
+ right: @control-padding-horizontal;
}
& &-keyword {
diff --git a/components/checkbox/Checkbox.jsx b/components/checkbox/Checkbox.jsx
index 763d3c32b..ba69b9616 100644
--- a/components/checkbox/Checkbox.jsx
+++ b/components/checkbox/Checkbox.jsx
@@ -55,7 +55,10 @@ export default {
} = props
const checkboxProps = { props: { ...restProps, prefixCls }, on: restListeners, attrs: getAttrs(this) }
if (checkboxGroup) {
- checkboxProps.on.change = () => checkboxGroup.toggleOption({ label: children, value: props.value })
+ checkboxProps.on.change = (...args) => {
+ this.$emit('change', ...args)
+ checkboxGroup.toggleOption({ label: children, value: props.value })
+ }
checkboxProps.props.checked = checkboxGroup.sValue.indexOf(props.value) !== -1
checkboxProps.props.disabled = props.disabled || checkboxGroup.disabled
} else {
@@ -63,6 +66,8 @@ export default {
}
const classString = classNames({
[`${prefixCls}-wrapper`]: true,
+ [`${prefixCls}-wrapper-checked`]: checkboxProps.props.checked,
+ [`${prefixCls}-wrapper-disabled`]: checkboxProps.props.disabled,
})
const checkboxClass = classNames({
[`${prefixCls}-indeterminate`]: indeterminate,
@@ -78,7 +83,7 @@ export default {
class={checkboxClass}
ref='vcCheckbox'
/>
- {children !== undefined ? {children} : null}
+ {children !== undefined && {children} }
)
},
diff --git a/components/checkbox/Group.jsx b/components/checkbox/Group.jsx
index 2ddc14655..4e2e8c989 100644
--- a/components/checkbox/Group.jsx
+++ b/components/checkbox/Group.jsx
@@ -1,6 +1,7 @@
import Checkbox from './Checkbox'
import hasProp from '../_util/props-util'
+function noop () {}
export default {
name: 'ACheckboxGroup',
props: {
@@ -82,7 +83,7 @@ export default {
disabled={'disabled' in option ? option.disabled : props.disabled}
value={option.value}
checked={state.sValue.indexOf(option.value) !== -1}
- onChange={() => this.toggleOption(option)}
+ onChange={option.onChange || noop}
class={`${groupPrefixCls}-item`}
>
{option.label}
diff --git a/components/checkbox/__tests__/__snapshots__/demo.test.js.snap b/components/checkbox/__tests__/__snapshots__/demo.test.js.snap
index e1b7c71a6..1a8b85542 100644
--- a/components/checkbox/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/checkbox/__tests__/__snapshots__/demo.test.js.snap
@@ -7,27 +7,27 @@ exports[`renders ./components/checkbox/demo/check-all.md correctly 1`] = `
Check all
- Apple Pear Orange
+ Apple Pear Orange
`;
exports[`renders ./components/checkbox/demo/controller.md correctly 1`] = `
`;
-exports[`renders ./components/checkbox/demo/disabled.md correctly 1`] = `
`;
+exports[`renders ./components/checkbox/demo/disabled.md correctly 1`] = `
`;
exports[`renders ./components/checkbox/demo/group.md correctly 1`] = `
`;
diff --git a/components/checkbox/__tests__/group.test.js b/components/checkbox/__tests__/group.test.js
index 1fd53a51f..d4db61bde 100644
--- a/components/checkbox/__tests__/group.test.js
+++ b/components/checkbox/__tests__/group.test.js
@@ -103,4 +103,21 @@ describe('CheckboxGroup', () => {
expect(wrapper.vm.sValue).toEqual(['Apple'])
})
})
+
+ // https://github.com/ant-design/ant-design/issues/12642
+ it('should trigger onChange in sub Checkbox', () => {
+ const onChange = jest.fn()
+ const wrapper = mount({
+ render () {
+ return (
+
+
+
+ )
+ },
+ })
+ wrapper.findAll('.ant-checkbox-input').at(0).trigger('change')
+ expect(onChange).toBeCalled()
+ expect(onChange.mock.calls[0][0].target.value).toEqual('my')
+ })
})
diff --git a/components/checkbox/demo/index.vue b/components/checkbox/demo/index.vue
index ca86cf930..8fd01a22f 100644
--- a/components/checkbox/demo/index.vue
+++ b/components/checkbox/demo/index.vue
@@ -29,6 +29,7 @@
category: 'Components',
subtitle: '多选框',
type: 'Data Entry',
+ zhType: '数据录入',
title: 'Checkbox',
render () {
return (
diff --git a/components/checkbox/index.en-US.md b/components/checkbox/index.en-US.md
index 592ea8f00..5471f0b9a 100644
--- a/components/checkbox/index.en-US.md
+++ b/components/checkbox/index.en-US.md
@@ -23,7 +23,7 @@
| -------- | ----------- | ---- | ------- |
| defaultValue | Default selected value | string\[] | \[] |
| disabled | Disable all checkboxes | boolean | false |
-| options | Specifies options | string\[] \| Array<{ label: string value: string disabled?: boolean }> | \[] |
+| options | Specifies options | string\[] \| Array<{ label: string value: string disabled?: boolean, onChange?: function }> | \[] |
| value | Used for setting the currently selected value. | string\[] | \[] |
#### events
diff --git a/components/checkbox/index.zh-CN.md b/components/checkbox/index.zh-CN.md
index aba61cbe2..ff59f2d50 100644
--- a/components/checkbox/index.zh-CN.md
+++ b/components/checkbox/index.zh-CN.md
@@ -25,9 +25,8 @@
| --- | --- | --- | --- |
| defaultValue | 默认选中的选项 | string\[] | \[] |
| disabled | 整组失效 | boolean | false |
-| options | 指定可选项 | string\[] \| Array<{ label: string value: string disabled?: boolean }> | \[] |
+| options | 指定可选项 | string\[] \| Array<{ label: string value: string disabled?: boolean, onChange?: function }> | \[] |
| value | 指定选中的选项 | string\[] | \[] |
-| onChange | 变化时回调函数 | Function(checkedValue) | - |
#### 事件
| 事件名称 | 说明 | 回调参数 |
diff --git a/components/checkbox/style/mixin.less b/components/checkbox/style/mixin.less
index f32d8dc12..81fc57010 100644
--- a/components/checkbox/style/mixin.less
+++ b/components/checkbox/style/mixin.less
@@ -28,7 +28,7 @@
height: 100%;
border-radius: @border-radius-sm;
border: 1px solid @checkbox-color;
- content: '';
+ content: "";
animation: antCheckboxEffect 0.36s ease-in-out;
animation-fill-mode: both;
visibility: hidden;
@@ -46,10 +46,13 @@
display: block;
width: @checkbox-size;
height: @checkbox-size;
- border: @border-width-base @border-style-base @border-color-base;
+ border: @checkbox-border-width @border-style-base @border-color-base;
border-radius: @border-radius-sm;
background-color: @checkbox-check-color;
transition: all .3s;
+ // Fix IE checked style
+ // https://github.com/ant-design/ant-design/issues/12597
+ border-collapse: separate;
&:after {
@check-width: (@checkbox-size / 14) * 5px;
@@ -84,25 +87,6 @@
}
}
- // 半选状态
- .@{checkbox-prefix-cls}-indeterminate .@{checkbox-inner-prefix-cls}:after {
- @indeterminate-width: @checkbox-size - 8px;
- @indeterminate-height: @checkbox-size - 8px;
- content: ' ';
- transform: translate(-50%, -50%) scale(1);
- border: 0;
- left: 50%;
- top: 50%;
- width: @indeterminate-width;
- height: @indeterminate-height;
- background-color: @checkbox-color;
- opacity: 1;
- }
-
- .@{checkbox-prefix-cls}-indeterminate.@{checkbox-prefix-cls}-disabled .@{checkbox-inner-prefix-cls}:after {
- border-color: @disabled-color;
- }
-
// 选中状态
.@{checkbox-prefix-cls}-checked .@{checkbox-inner-prefix-cls}:after {
transform: rotate(45deg) scale(1);
@@ -143,6 +127,7 @@
&:after {
animation-name: none;
border-color: @input-disabled-bg;
+ border-collapse: separate;
}
}
@@ -182,6 +167,32 @@
margin-left: 0;
}
}
+
+ // 半选状态
+ .@{checkbox-prefix-cls}-indeterminate {
+ .@{checkbox-inner-prefix-cls} {
+ background-color: #fff;
+ border-color: @border-color-base;
+ }
+ .@{checkbox-inner-prefix-cls}:after {
+ @indeterminate-width: @checkbox-size - 8px;
+ @indeterminate-height: @checkbox-size - 8px;
+ content: ' ';
+ transform: translate(-50%, -50%) scale(1);
+ border: 0;
+ left: 50%;
+ top: 50%;
+ width: @indeterminate-width;
+ height: @indeterminate-height;
+ background-color: @checkbox-color;
+ opacity: 1;
+ }
+
+ &.@{checkbox-prefix-cls}-disabled .@{checkbox-inner-prefix-cls}:after {
+ border-color: @disabled-color;
+ background-color: @disabled-color;
+ }
+ }
}
@keyframes antCheckboxEffect {
diff --git a/components/collapse/Collapse.jsx b/components/collapse/Collapse.jsx
index c0a850bea..05e9f4c57 100644
--- a/components/collapse/Collapse.jsx
+++ b/components/collapse/Collapse.jsx
@@ -1,9 +1,7 @@
-
-import PropTypes from '../_util/vue-types'
import animation from '../_util/openAnimation'
import { getOptionProps, initDefaultProps } from '../_util/props-util'
import VcCollapse, { collapseProps } from '../vc-collapse'
-
+import Icon from '../icon'
export default {
name: 'ACollapse',
model: {
@@ -15,6 +13,13 @@ export default {
bordered: true,
openAnimation: animation,
}),
+ methods: {
+ renderExpandIcon () {
+ return (
+
+ )
+ },
+ },
render () {
const { prefixCls, bordered, $listeners } = this
const collapseClassName = {
@@ -23,6 +28,7 @@ export default {
const rcCollapeProps = {
props: {
...getOptionProps(this),
+ expandIcon: this.renderExpandIcon,
},
class: collapseClassName,
on: $listeners,
diff --git a/components/collapse/__tests__/__snapshots__/demo.test.js.snap b/components/collapse/__tests__/__snapshots__/demo.test.js.snap
index 07d713e20..64c2ddc04 100644
--- a/components/collapse/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/collapse/__tests__/__snapshots__/demo.test.js.snap
@@ -4,15 +4,21 @@ exports[`renders ./components/collapse/demo/accordion.md correctly 1`] = `
@@ -23,7 +29,9 @@ exports[`renders ./components/collapse/demo/basic.md correctly 1`] = `
-
+
A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.
@@ -31,11 +39,15 @@ exports[`renders ./components/collapse/demo/basic.md correctly 1`] = `
-
+
-
+
@@ -46,7 +58,9 @@ exports[`renders ./components/collapse/demo/borderless.md correctly 1`] = `
-
+
A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.
@@ -54,11 +68,15 @@ exports[`renders ./components/collapse/demo/borderless.md correctly 1`] = `
-
+
-
+
@@ -69,8 +87,13 @@ exports[`renders ./components/collapse/demo/custom.md correctly 1`] = `
-
+
A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.
@@ -78,11 +101,15 @@ exports[`renders ./components/collapse/demo/custom.md correctly 1`] = `
-
+
-
+
@@ -93,15 +120,21 @@ exports[`renders ./components/collapse/demo/mix.md correctly 1`] = `
@@ -112,7 +145,9 @@ exports[`renders ./components/collapse/demo/noarrow.md correctly 1`] = `
-
+
A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.
diff --git a/components/collapse/demo/index.vue b/components/collapse/demo/index.vue
index 3a671fb60..3536dd1e5 100644
--- a/components/collapse/demo/index.vue
+++ b/components/collapse/demo/index.vue
@@ -29,6 +29,7 @@ const md = {
export default {
category: 'Components',
type: 'Data Display',
+ zhType: '数据展示',
title: 'Collapse',
subtitle: '折叠面板',
cols: 1,
diff --git a/components/collapse/style/index.less b/components/collapse/style/index.less
index 622f48d32..74447fb11 100644
--- a/components/collapse/style/index.less
+++ b/components/collapse/style/index.less
@@ -37,17 +37,17 @@
.arrow {
.iconfont-mixin();
- .collapse-close();
font-size: @font-size-sm;
position: absolute;
display: inline-block;
line-height: 46px;
vertical-align: top;
- transition: transform 0.24s;
- top: 0;
+ top: 50%;
+ transform: translateY(-50%);
left: @padding-md;
- &:before {
- content: "\E61F";
+ & svg {
+ .collapse-close();
+ transition: transform 0.24s;
}
}
@@ -89,7 +89,7 @@
}
& > &-item > &-header[aria-expanded="true"] {
- .arrow {
+ .anticon-right svg {
.collapse-open();
}
}
diff --git a/components/date-picker/RangePicker.jsx b/components/date-picker/RangePicker.jsx
index f65d572f6..e62240197 100644
--- a/components/date-picker/RangePicker.jsx
+++ b/components/date-picker/RangePicker.jsx
@@ -8,8 +8,9 @@ import Icon from '../icon'
import Tag from '../tag'
import interopDefault from '../_util/interopDefault'
import { RangePickerProps } from './interface'
-import { hasProp, getOptionProps, initDefaultProps, mergeProps } from '../_util/props-util'
+import { hasProp, getOptionProps, initDefaultProps, mergeProps, getComponentFromProp, isValidElement } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
+import { cloneElement } from '../_util/vnode'
function noop () {}
function getShowDateFromValue (value) {
const [start, end] = value
@@ -130,6 +131,7 @@ export default {
formatValue(value[0], this.format),
formatValue(value[1], this.format),
])
+ this.focus()
},
handleOpenChange (open) {
@@ -174,6 +176,7 @@ export default {
this.setValue(value, true)
this.$emit('ok', value)
+ this.$emit('openChange', false)
},
setValue (value, hidePanel) {
@@ -224,17 +227,18 @@ export default {
)
})
- const rangeNode = (
+ const rangeNode = (operations && operations.length > 0) ? (
- )
+
) : null
return [rangeNode, customFooter]
},
},
render () {
const props = getOptionProps(this)
+ let suffixIcon = getComponentFromProp(this, 'suffixIcon')
+ suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon
const { sValue: value, sShowDate: showDate, sHoverValue: hoverValue, sOpen: open, $listeners, $scopedSlots } = this
const { calendarChange = noop, ok = noop, focus = noop, blur = noop, panelChange = noop } = $listeners
const {
@@ -296,7 +300,7 @@ export default {
ok: ok,
valueChange: this.handleShowDateChange,
hoverChange: this.handleHoverChange,
- panelChange: panelChange,
+ panelChange,
inputSelect: this.handleCalendarInputSelect,
},
class: calendarClassName,
@@ -316,12 +320,24 @@ export default {
const clearIcon = (!props.disabled && props.allowClear && value && (value[0] || value[1])) ? (
) : null
+ const inputIcon = suffixIcon && (
+ isValidElement(suffixIcon)
+ ? cloneElement(
+ suffixIcon,
+ {
+ class: `${prefixCls}-picker-icon`,
+ },
+ ) :
{suffixIcon} ) || (
+
+ )
+
const input = ({ value: inputValue }) => {
const start = inputValue[0]
const end = inputValue[1]
@@ -345,7 +361,7 @@ export default {
tabIndex={-1}
/>
{clearIcon}
-
+ {inputIcon}
)
}
diff --git a/components/date-picker/WeekPicker.jsx b/components/date-picker/WeekPicker.jsx
index bd3fa6bf6..d7526e6bf 100644
--- a/components/date-picker/WeekPicker.jsx
+++ b/components/date-picker/WeekPicker.jsx
@@ -3,10 +3,11 @@ import * as moment from 'moment'
import Calendar from '../vc-calendar'
import VcDatePicker from '../vc-calendar/src/Picker'
import Icon from '../icon'
-import { hasProp, getOptionProps, initDefaultProps } from '../_util/props-util'
+import { hasProp, getOptionProps, initDefaultProps, getComponentFromProp, isValidElement } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
import { WeekPickerProps } from './interface'
import interopDefault from '../_util/interopDefault'
+import { cloneElement } from '../_util/vnode'
function formatValue (value, format) {
return (value && value.format(format)) || ''
@@ -74,6 +75,7 @@ export default {
this.setState({ sValue: value })
}
this.$emit('change', value, formatValue(value, this.format))
+ this.focus()
},
clearSelection (e) {
e.preventDefault()
@@ -92,6 +94,8 @@ export default {
render () {
const props = getOptionProps(this)
+ let suffixIcon = getComponentFromProp(this, 'suffixIcon')
+ suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon
const {
prefixCls, disabled, pickerClass, popupStyle,
pickerInputClass, format, allowClear, locale, localeCode, disabledDate,
@@ -119,11 +123,24 @@ export default {
)
const clearIcon = (!disabled && allowClear && this.sValue) ? (
) : null
+
+ const inputIcon = suffixIcon && (
+ isValidElement(suffixIcon)
+ ? cloneElement(
+ suffixIcon,
+ {
+ class: `${prefixCls}-picker-icon`,
+ },
+ ) :
{suffixIcon} ) || (
+
+ )
+
const input = ({ value }) => {
return (
@@ -138,7 +155,7 @@ export default {
onBlur={blur}
/>
{clearIcon}
-
+ {inputIcon}
)
}
diff --git a/components/date-picker/__tests__/DatePicker.test.js b/components/date-picker/__tests__/DatePicker.test.js
index 26b9c4b57..6eed25bf0 100644
--- a/components/date-picker/__tests__/DatePicker.test.js
+++ b/components/date-picker/__tests__/DatePicker.test.js
@@ -146,41 +146,38 @@ describe('DatePicker', () => {
}, { sync: false, attachToDocument: true })
await asyncExpect(() => {
openPanel(wrapper)
- })
+ }, 0)
await asyncExpect(() => {
nextYear()
+ }, 1000)
+ await asyncExpect(() => {
+ expect(handleChange).not.toBeCalled()
+ }, 0)
+ await asyncExpect(() => {
+ nextMonth()
}, 0)
await asyncExpect(() => {
expect(handleChange).not.toBeCalled()
})
- await asyncExpect(() => {
- nextMonth()
- })
- await asyncExpect(() => {
- expect(handleChange).not.toBeCalled()
- })
await asyncExpect(() => {
selectDateFromBody(moment('2017-12-22'))
- })
+ }, 1000)
await asyncExpect(() => {
expect(handleChange).toBeCalled()
- })
- await asyncExpect(() => {
-
- })
+ }, 0)
})
it('clear input', async () => {
const wrapper = mount(DatePicker, { sync: false, attachToDocument: true })
await asyncExpect(() => {
openPanel(wrapper)
- })
- await asyncExpect(() => {
- selectDateFromBody(moment('2016-11-23'))
}, 0)
+ await asyncExpect(() => {
+ selectDateFromBody(moment('2016-11-23'))
+ }, 100)
await asyncExpect(() => {
clearInput(wrapper)
- }, 300)
+ }, 1000)
await asyncExpect(() => {
openPanel(wrapper)
}, 0)
diff --git a/components/date-picker/__tests__/MonthPicker.test.js b/components/date-picker/__tests__/MonthPicker.test.js
index 2e115e9af..f0cf2e6c5 100644
--- a/components/date-picker/__tests__/MonthPicker.test.js
+++ b/components/date-picker/__tests__/MonthPicker.test.js
@@ -1,8 +1,26 @@
+import { mount } from '@vue/test-utils'
+import { asyncExpect } from '@/tests/utils'
+import moment from 'moment'
import DatePicker from '..'
import focusTest from '../../../tests/shared/focusTest'
+import { openPanel, $$ } from './utils'
const { MonthPicker } = DatePicker
describe('MonthPicker', () => {
focusTest(MonthPicker)
+ it('reset select item when popup close', async () => {
+ const wrapper = mount(MonthPicker, {
+ propsData: { value: moment('2018-07-01') },
+ sync: false,
+ attachToDocument: true,
+ })
+ await asyncExpect(() => {
+ openPanel(wrapper)
+ })
+ await asyncExpect(() => {
+ $$('.ant-calendar-month-panel-month')[0].click()
+ $$('.ant-calendar-month-panel-cell')[6].getAttribute('class').split(' ').includes('ant-calendar-month-panel-selected-cell')
+ }, 0)
+ })
})
diff --git a/components/date-picker/__tests__/RangePicker.test.js b/components/date-picker/__tests__/RangePicker.test.js
index 84abd5dde..6d0854b21 100644
--- a/components/date-picker/__tests__/RangePicker.test.js
+++ b/components/date-picker/__tests__/RangePicker.test.js
@@ -325,4 +325,26 @@ describe('RangePicker', () => {
}).not.toThrow()
})
})
+ // https://github.com/ant-design/ant-design/issues/11631
+ it('triggers onOpenChange when click on preset range', async () => {
+ const handleOpenChange = jest.fn()
+ const range = [moment().subtract(2, 'd'), moment()]
+ const wrapper = mount({
+ render () {
+ return
+ },
+ }, {
+ sync: false,
+ attachToDocument: true,
+ })
+ await asyncExpect(() => {
+ wrapper.find('.ant-calendar-picker-input').trigger('click')
+ })
+ await asyncExpect(() => {
+ $$('.ant-calendar-range-quick-selector .ant-tag')[0].click()
+ }, 0)
+ await asyncExpect(() => {
+ expect(handleOpenChange).toBeCalledWith(false)
+ })
+ })
})
diff --git a/components/date-picker/__tests__/__snapshots__/DatePicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/DatePicker.test.js.snap
index 0fa634fcb..1a318dbe4 100644
--- a/components/date-picker/__tests__/__snapshots__/DatePicker.test.js.snap
+++ b/components/date-picker/__tests__/__snapshots__/DatePicker.test.js.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`DatePicker prop locale should works 1`] = `
`;
+exports[`DatePicker prop locale should works 1`] = `
`;
diff --git a/components/date-picker/__tests__/__snapshots__/RangePicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/RangePicker.test.js.snap
index bba446b62..fd891fc39 100644
--- a/components/date-picker/__tests__/__snapshots__/RangePicker.test.js.snap
+++ b/components/date-picker/__tests__/__snapshots__/RangePicker.test.js.snap
@@ -687,7 +687,11 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
-
+
diff --git a/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap
index 1ced1846f..e77c56ad6 100644
--- a/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap
+++ b/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`WeekPicker should support style prop 1`] = `
`;
+exports[`WeekPicker should support style prop 1`] = `
`;
diff --git a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap
index 04454334c..6c1e5f529 100644
--- a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap
@@ -1,27 +1,77 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`renders ./components/date-picker/demo/basic.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/basic.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/date-render.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/date-render.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/disabled.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/disabled.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/disabled-date.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/disabled-date.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/extra-footer.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/extra-footer.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/format.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/format.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/mode.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/mode.md correctly 1`] = `
+
+`;
-exports[`renders ./components/date-picker/demo/presetted-ranges.md correctly 1`] = `
~ ~
`;
+exports[`renders ./components/date-picker/demo/presetted-ranges.md correctly 1`] = `
+
+`;
exports[`renders ./components/date-picker/demo/size.md correctly 1`] = `
+
Large Default Small
~
+
+
+
`;
-exports[`renders ./components/date-picker/demo/start-end.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/start-end.md correctly 1`] = `
`;
-exports[`renders ./components/date-picker/demo/time.md correctly 1`] = `
`;
+exports[`renders ./components/date-picker/demo/suffix.md correctly 1`] = `
+
+`;
+
+exports[`renders ./components/date-picker/demo/time.md correctly 1`] = `
+
+`;
diff --git a/components/date-picker/createPicker.js b/components/date-picker/createPicker.js
index 14ba81bb9..d74f49fd2 100644
--- a/components/date-picker/createPicker.js
+++ b/components/date-picker/createPicker.js
@@ -7,7 +7,8 @@ import classNames from 'classnames'
import Icon from '../icon'
import interopDefault from '../_util/interopDefault'
import BaseMixin from '../_util/BaseMixin'
-import { hasProp, getOptionProps, initDefaultProps, mergeProps } from '../_util/props-util'
+import { hasProp, getOptionProps, initDefaultProps, mergeProps, getComponentFromProp, isValidElement } from '../_util/props-util'
+import { cloneElement } from '../_util/vnode'
// export const PickerProps = {
// value?: moment.Moment;
@@ -44,14 +45,26 @@ export default function createPicker (TheCalendar, props) {
return {
sValue: value,
showDate: value,
+ _open: !!this.open,
}
},
watch: {
+ open (val) {
+ const props = getOptionProps(this)
+ const state = {}
+ state._open = val
+ if ('value' in props && !val && props.value !== this.showDate) {
+ state.showDate = props.value
+ }
+ this.setState(state)
+ },
value (val) {
- this.setState({
- sValue: val,
- showDate: val,
- })
+ const state = {}
+ state.sValue = val
+ if (val !== this.sValue) {
+ state.showDate = val
+ }
+ this.setState(state)
},
},
methods: {
@@ -79,12 +92,19 @@ export default function createPicker (TheCalendar, props) {
})
}
this.$emit('change', value, (value && value.format(this.format)) || '')
+ this.focus()
},
handleCalendarChange (value) {
this.setState({ showDate: value })
},
-
+ handleOpenChange (open) {
+ const props = getOptionProps(this)
+ if (!('open' in props)) {
+ this.setState({ _open: open })
+ }
+ this.$emit('openChange', open)
+ },
focus () {
this.$refs.input.focus()
},
@@ -101,7 +121,10 @@ export default function createPicker (TheCalendar, props) {
},
render () {
- const { sValue: value, showDate, $listeners, $scopedSlots } = this
+ const { $listeners, $scopedSlots } = this
+ const { sValue: value, showDate, _open: open } = this.$data
+ let suffixIcon = getComponentFromProp(this, 'suffixIcon')
+ suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon
const { panelChange = noop, focus = noop, blur = noop, ok = noop } = $listeners
const props = getOptionProps(this)
const { prefixCls, locale, localeCode } = props
@@ -123,9 +146,11 @@ export default function createPicker (TheCalendar, props) {
const pickerProps = { props: {}, on: {}}
const calendarProps = { props: {}, on: {}}
+ const pickerStyle = {}
if (props.showTime) {
// fix https://github.com/ant-design/ant-design/issues/1902
calendarProps.on.select = this.handleChange
+ pickerStyle.width = '195px'
} else {
pickerProps.on.change = this.handleChange
}
@@ -150,7 +175,7 @@ export default function createPicker (TheCalendar, props) {
},
on: {
ok: ok,
- panelChange: panelChange,
+ panelChange,
change: this.handleCalendarChange,
},
class: calendarClassName,
@@ -164,12 +189,24 @@ export default function createPicker (TheCalendar, props) {
const clearIcon = (!props.disabled && props.allowClear && value) ? (
) : null
+ const inputIcon = suffixIcon && (
+ isValidElement(suffixIcon)
+ ? cloneElement(
+ suffixIcon,
+ {
+ class: `${prefixCls}-picker-icon`,
+ },
+ ) :
{suffixIcon} ) || (
+
+ )
+
const input = ({ value: inputValue }) => (
{clearIcon}
-
+ {inputIcon}
)
const vcDatePickerProps = {
@@ -197,12 +235,15 @@ export default function createPicker (TheCalendar, props) {
on: {
...omit($listeners, 'change'),
...pickerProps.on,
+ open,
+ onOpenChange: this.handleOpenChange,
},
style: props.popupStyle,
}
return (
-
+
diff --git a/components/date-picker/demo/suffix.md b/components/date-picker/demo/suffix.md
new file mode 100644
index 000000000..984a7418c
--- /dev/null
+++ b/components/date-picker/demo/suffix.md
@@ -0,0 +1,51 @@
+
+
+#### 后缀图标
+最简单的用法,在浮层中可以选择或者输入日期。
+
+
+
+#### Suffix
+Basic use case. Users can select or input a date in panel.
+
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md
index a3ebc9152..093879d03 100644
--- a/components/date-picker/index.en-US.md
+++ b/components/date-picker/index.en-US.md
@@ -11,7 +11,7 @@ There are four kinds of picker:
**Note:** Part of locale of DatePicker, MonthPicker, RangePicker, WeekPicker is read from value. So, please set the locale of moment correctly.
````html
-// The default locale is en-US, if you want to use other locale, just set locale in entry file globaly.
+// The default locale is en-US, if you want to use other locale, just set locale in entry file globally.
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
@@ -37,11 +37,14 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| popupStyle | to customize the style of the popup calendar | object | {} |
| dropdownClassName | to customize the className of the popup calendar | string | - |
| size | determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | string | - |
+| suffixIcon | The custom suffix icon | VNode \| slot | - |
### Common Events
| Events Name | Description | Arguments |
| --- | --- | --- |
| openChange | a callback function, can be executed whether the popup calendar is popped up or closed | function(status) |
+| panelChange | callback when picker panel mode is changed | function(value, mode) |
+
### Common Methods
@@ -55,6 +58,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| defaultValue | to set default date | [moment](http://momentjs.com/) | - |
+| defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - |
| disabledTime | to specify the time that cannot be selected | function(date) | - |
| format | to set the date format, refer to [moment.js](http://momentjs.com/) | string | "YYYY-MM-DD" |
| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" | - |
@@ -75,6 +79,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| defaultValue | to set default date | [moment](http://momentjs.com/) | - |
+| defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - |
| format | to set the date format, refer to [moment.js](http://momentjs.com/) | string | "YYYY-MM" |
| monthCellContentRender | Custom month cell content render method by setting a scoped slot | slot="monthCellContentRender" slot-scope="date, locale" | - |
| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" | - |
@@ -90,6 +95,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| defaultValue | to set default date | [moment](http://momentjs.com/) | - |
+| defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - |
| format | to set the date format, refer to [moment.js](http://momentjs.com/) | string | "YYYY-wo" |
| value(v-model) | to set date | [moment](http://momentjs.com/) | - |
@@ -103,9 +109,10 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| defaultValue | to set default date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - |
+| defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - |
| disabledTime | to specify the time that cannot be selected | function(dates: [moment, moment], partial: `'start'|'end'`) | - |
| format | to set the date format | string | "YYYY-MM-DD HH:mm:ss" |
-| ranges | preseted ranges for quick selection | { \[range: string\]: [moment](http://momentjs.com/)\[] } \| () => { \[range: string\]: [moment](http://momentjs.com/)\[] } | - |
+| ranges | preseted ranges for quick selection | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | - |
| renderExtraFooter | render extra footer in panel by setting a scoped slot| slot="renderExtraFooter" | - |
| showTime | to provide an additional time selection | object\|boolean | [TimePicker Options](/ant-design-vue/components/time-picker/#API) |
| showTime.defaultValue | to set default time of selected date, [demo](https://ant.design/components/date-picker/#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/)\[] | [moment(), moment()] |
@@ -114,6 +121,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
### RangePicker Events
| Events Name | Description | Arguments |
| --- | --- | --- |
+| calendarChange | a callback function, can be executed when the start time or the end time of the range is changing | function(dates: [moment, moment], dateStrings: [string, string]) |
| change | a callback function, can be executed when the selected time is changing | function(dates: [moment, moment], dateStrings: [string, string]) |
| ok | callback when click ok button | function() |
diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md
index 4bd9928fe..b5d9269de 100644
--- a/components/date-picker/index.zh-CN.md
+++ b/components/date-picker/index.zh-CN.md
@@ -12,9 +12,9 @@
````html
// 默认语言为 en-US,如果你需要设置其他语言,推荐在入口文件全局设置 locale
-// import moment from 'moment';
-// import 'moment/locale/zh-cn';
-// moment.locale('zh-cn');
+import moment from 'moment';
+import 'moment/locale/zh-cn';
+moment.locale('zh-cn');
````
@@ -37,12 +37,14 @@
| popupStyle | 额外的弹出日历样式 | object | {} |
| dropdownClassName | 额外的弹出日历 className | string | - |
| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | string | 无 |
+| suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - |
### 共有的事件
| 事件名称 | 说明 | 回调参数 |
| --- | --- | --- |
| openChange | 弹出日历和关闭日历的回调 | function(status) |
+| panelChange | 日期面板变化时的回调 | function(value, mode) | - |
### 共同的方法
@@ -56,6 +58,7 @@
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认日期 | [moment](http://momentjs.com/) | 无 |
+| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 |
| disabledTime | 不可选择的时间 | function(date) | 无 |
| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM-DD" |
| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - |
@@ -76,6 +79,7 @@
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认日期 | [moment](http://momentjs.com/) | 无 |
+| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 |
| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM" |
| monthCellContentRender | 自定义的月份内容渲染方法 | slot="monthCellContentRender" slot-scope="date, locale" | - |
| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - |
@@ -92,6 +96,7 @@
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认日期 | [moment](http://momentjs.com/) | - |
+| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 |
| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-wo" |
| value(v-model) | 日期 | [moment](http://momentjs.com/) | - |
@@ -106,9 +111,10 @@
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认日期 | [moment](http://momentjs.com/)\[] | 无 |
+| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 |
| disabledTime | 不可选择的时间 | function(dates: [moment, moment], partial: `'start'|'end'`) | 无 |
| format | 展示的日期格式 | string | "YYYY-MM-DD HH:mm:ss" |
-| ranges | 预设时间范围快捷选择 | { \[range: string\]: [moment](http://momentjs.com/)\[] } \| () => { \[range: string\]: [moment](http://momentjs.com/)\[] } | 无 |
+| ranges | 预设时间范围快捷选择 | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | 无 |
| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - |
| showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/ant-design-vue/components/time-picker-cn/#API) |
| showTime.defaultValue | 设置用户选择日期时默认的时分秒 | [moment](http://momentjs.com/)\[] | [moment(), moment()] |
diff --git a/components/date-picker/interface.js b/components/date-picker/interface.js
index 5c3929341..42b1a37c2 100644
--- a/components/date-picker/interface.js
+++ b/components/date-picker/interface.js
@@ -16,6 +16,7 @@ export const PickerProps = () => ({
format: PropTypes.string,
disabled: PropTypes.bool,
allowClear: PropTypes.bool,
+ suffixIcon: PropTypes.any,
popupStyle: PropTypes.object,
dropdownClassName: PropTypes.string,
locale: PropTypes.any,
@@ -33,6 +34,7 @@ export const PickerProps = () => ({
timePicker: PropTypes.any,
autoFocus: PropTypes.bool,
tagPrefixCls: PropTypes.string,
+ tabIndex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
})
export const SinglePickerProps = () => ({
diff --git a/components/date-picker/locale/mn_MN.js b/components/date-picker/locale/mn_MN.js
new file mode 100644
index 000000000..485403126
--- /dev/null
+++ b/components/date-picker/locale/mn_MN.js
@@ -0,0 +1,19 @@
+import CalendarLocale from '../../vc-calendar/src/locale/mn_MN'
+import TimePickerLocale from '../../time-picker/locale/mn_MN'
+
+// Merge into a locale object
+const locale = {
+ lang: {
+ placeholder: 'Огноо сонгох',
+ rangePlaceholder: ['Эхлэх огноо', 'Дуусах огноо'],
+ ...CalendarLocale,
+ },
+ timePickerLocale: {
+ ...TimePickerLocale,
+ },
+}
+
+// All settings at:
+// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
+
+export default locale
diff --git a/components/date-picker/locale/vi_VN.js b/components/date-picker/locale/vi_VN.js
index 65fe299a8..9219e73e9 100644
--- a/components/date-picker/locale/vi_VN.js
+++ b/components/date-picker/locale/vi_VN.js
@@ -1,5 +1,5 @@
-import CalendarLocale from '../../vc-calendar/src/locale/en_US'
-import TimePickerLocale from '../../time-picker/locale/en_US'
+import CalendarLocale from '../../vc-calendar/src/locale/vi_VN'
+import TimePickerLocale from '../../time-picker/locale/vi_VN'
// Merge into a locale object
const locale = {
diff --git a/components/date-picker/style/Calendar.less b/components/date-picker/style/Calendar.less
index df76e508f..93fed470d 100644
--- a/components/date-picker/style/Calendar.less
+++ b/components/date-picker/style/Calendar.less
@@ -275,10 +275,8 @@
text-align: center;
display: block;
}
- &-extra + &-btn {
- border-top: @border-width-base @border-style-base @border-color-split;
- margin: 0 -12px;
- padding: 0 12px;
+ &-extra {
+ text-align: left;
}
}
@@ -311,7 +309,6 @@
}
.@{calendar-prefix-cls}-clear-btn:after {
- .iconfont-font("\e62e");
font-size: @font-size-base;
color: @disabled-color;
display: inline-block;
diff --git a/components/date-picker/style/Picker.less b/components/date-picker/style/Picker.less
index 88adf1747..b9b085a88 100644
--- a/components/date-picker/style/Picker.less
+++ b/components/date-picker/style/Picker.less
@@ -42,6 +42,11 @@
outline: none;
}
+ &-input.@{ant-prefix}-input-sm {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
&:hover &-input:not(.@{ant-prefix}-input-disabled) {
border-color: @primary-color;
}
@@ -62,11 +67,13 @@
font-size: @font-size-sm;
transition: all .3s;
user-select: none;
+ z-index: 1;
}
&-clear {
opacity: 0;
- z-index: 1;
+ z-index: 2;
+ font-size: @font-size-base;
color: @disabled-color;
background: @input-bg;
pointer-events: none;
@@ -82,15 +89,11 @@
}
&-icon {
+ font-family: "anticon";
+ font-size: @font-size-base;
color: @disabled-color;
- &:after {
- content: "\e6bb";
- font-family: "anticon";
- font-size: @font-size-base;
- color: @disabled-color;
- display: inline-block;
- line-height: 1;
- }
+ display: inline-block;
+ line-height: 1;
}
&-small &-clear,
diff --git a/components/date-picker/style/RangePicker.less b/components/date-picker/style/RangePicker.less
index 048309fa3..62cfe035d 100644
--- a/components/date-picker/style/RangePicker.less
+++ b/components/date-picker/style/RangePicker.less
@@ -134,7 +134,7 @@
z-index: 1;
}
&:before {
- content: '';
+ content: "";
display: block;
background: @item-active-bg;
border-radius: 0;
@@ -147,6 +147,10 @@
}
}
+ .@{calendar-prefix-cls}-footer-extra {
+ float: left;
+ }
+
// `div` for selector specificity
div&-quick-selector {
text-align: left;
diff --git a/components/date-picker/style/TimePicker.less b/components/date-picker/style/TimePicker.less
index 25e080cdc..6bda07546 100644
--- a/components/date-picker/style/TimePicker.less
+++ b/components/date-picker/style/TimePicker.less
@@ -90,7 +90,7 @@
}
li:last-child:after {
- content: '';
+ content: "";
height: 202px;
display: block;
}
diff --git a/components/date-picker/wrapPicker.js b/components/date-picker/wrapPicker.js
index 144b6937f..de359f531 100644
--- a/components/date-picker/wrapPicker.js
+++ b/components/date-picker/wrapPicker.js
@@ -1,4 +1,3 @@
-
import TimePickerPanel from '../vc-time-picker/Panel'
import classNames from 'classnames'
import LocaleReceiver from '../locale-provider/LocaleReceiver'
@@ -147,9 +146,11 @@ export default function wrapPicker (Picker, props, defaultFormat) {
-
- {this.$slots.renderExtraFooter}
-
+ {this.$slots && Object.keys(this.$slots).map(key => (
+
+ {this.$slots[key]}
+
+ ))}
)
},
diff --git a/components/divider/demo/index.vue b/components/divider/demo/index.vue
index 7a0d89995..a4078213b 100644
--- a/components/divider/demo/index.vue
+++ b/components/divider/demo/index.vue
@@ -23,6 +23,7 @@ const md = {
export default {
category: 'Components',
type: 'Other',
+ zhType: '其他',
title: 'Divider',
subtitle: '分割线',
render () {
diff --git a/components/divider/style/index.less b/components/divider/style/index.less
index 926865fea..c7e641189 100644
--- a/components/divider/style/index.less
+++ b/components/divider/style/index.less
@@ -21,6 +21,7 @@
display: block;
height: 1px;
width: 100%;
+ min-width: 100%; // Fix https://github.com/ant-design/ant-design/issues/10914
margin: 24px 0;
clear: both;
}
@@ -38,7 +39,7 @@
margin: 16px 0;
&:before,
&:after {
- content: '';
+ content: "";
display: table-cell;
position: relative;
top: 50%;
diff --git a/components/drawer/__tests__/Drawer.test.js b/components/drawer/__tests__/Drawer.test.js
index bc684587f..ae8364132 100644
--- a/components/drawer/__tests__/Drawer.test.js
+++ b/components/drawer/__tests__/Drawer.test.js
@@ -57,6 +57,25 @@ describe('Drawer', () => {
})
})
+ it('render top drawer', async () => {
+ const props = {
+ propsData: {
+ visible: true,
+ height: 400,
+ placement: 'top',
+ getContainer: false,
+ },
+ slots: {
+ default: 'Here is content of Drawer',
+ },
+ sync: false,
+ }
+ const wrapper = mount(Drawer, props)
+ await asyncExpect(() => {
+ expect(wrapper.html()).toMatchSnapshot()
+ })
+ })
+
it('have a title', async () => {
const props = {
propsData: {
diff --git a/components/drawer/__tests__/MultiDrawer.test.js b/components/drawer/__tests__/MultiDrawer.test.js
index 8346e776f..8e84fb23b 100644
--- a/components/drawer/__tests__/MultiDrawer.test.js
+++ b/components/drawer/__tests__/MultiDrawer.test.js
@@ -2,7 +2,9 @@ import { mount } from '@vue/test-utils'
import Drawer from '..'
import Button from '../../button'
import { asyncExpect } from '@/tests/utils'
-
+export function $$ (className) {
+ return document.body.querySelectorAll(className)
+}
const MultiDrawer = {
props: {
placement: {
@@ -27,6 +29,7 @@ const MultiDrawer = {
this.childrenDrawer = true
},
onChildrenDrawerClose () {
+ console.log('hello')
this.childrenDrawer = false
},
},
@@ -35,7 +38,6 @@ const MultiDrawer = {
props: {
title: 'Multi-level drawer',
width: 520,
- closable: false,
visible: this.visible,
getContainer: false,
wrapClassName: 'test_drawer',
@@ -49,7 +51,7 @@ const MultiDrawer = {
props: {
title: 'Two-level Drawer',
width: 320,
- closable: false,
+ wrapClassName: 'Two-level',
visible: this.childrenDrawer,
getContainer: false,
placement: this.placement,
@@ -137,7 +139,7 @@ describe('Drawer', () => {
}, 1000)
})
- it('render right MultiDrawer', async () => {
+ it('render left MultiDrawer', async () => {
document.body.innerHTML = ''
const wrapper = mount(MultiDrawer, {
propsData: {
@@ -157,4 +159,24 @@ describe('Drawer', () => {
expect(wrapper.find('#two_drawer_text').exists()).toBe(true)
}, 1000)
})
+
+ it('render top MultiDrawer', async () => {
+ const wrapper = mount(MultiDrawer, {
+ propsData: {
+ placement: 'top',
+ },
+ sync: false,
+ })
+ await asyncExpect(() => {
+ wrapper.find('#open_drawer').trigger('click')
+ }, 0)
+ await asyncExpect(() => {
+ wrapper.find('#open_two_drawer').trigger('click')
+ }, 0)
+ await asyncExpect(() => {
+ const translateY = wrapper.find('.ant-drawer.test_drawer').element.parentElement.style.transform
+ expect(translateY).toEqual('translateY(180px)')
+ expect(wrapper.find('#two_drawer_text').exists()).toBe(true)
+ }, 1000)
+ })
})
diff --git a/components/drawer/__tests__/__snapshots__/Drawer.test.js.snap b/components/drawer/__tests__/__snapshots__/Drawer.test.js.snap
index 18ab0f66a..688d5207a 100644
--- a/components/drawer/__tests__/__snapshots__/Drawer.test.js.snap
+++ b/components/drawer/__tests__/__snapshots__/Drawer.test.js.snap
@@ -6,7 +6,7 @@ exports[`Drawer class is test_drawer 1`] = `
-
+
Here is content of Drawer
@@ -54,7 +54,7 @@ exports[`Drawer have a title 1`] = `
+
Here is content of Drawer
@@ -69,7 +69,22 @@ exports[`Drawer render correctly 1`] = `
-
+
+
Here is content of Drawer
+
+
+
+
+
+`;
+
+exports[`Drawer render top drawer 1`] = `
+
+
+
+
+
+
Here is content of Drawer
diff --git a/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap b/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap
index d63d6cd14..efd6a7c4e 100644
--- a/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap
+++ b/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap
@@ -7,7 +7,7 @@ exports[`Drawer render correctly 1`] = `
-
+
Here is content of Drawer
diff --git a/components/drawer/__tests__/__snapshots__/demo.test.js.snap b/components/drawer/__tests__/__snapshots__/demo.test.js.snap
index ecadb932f..5723e2095 100644
--- a/components/drawer/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/drawer/__tests__/__snapshots__/demo.test.js.snap
@@ -1,11 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`renders ./components/drawer/demo/basic-left.md correctly 1`] = `
-
Open
-
-
-`;
-
exports[`renders ./components/drawer/demo/basic-right.md correctly 1`] = `
Open
@@ -18,6 +12,13 @@ exports[`renders ./components/drawer/demo/multi-level-drawer.md correctly 1`] =
`;
+exports[`renders ./components/drawer/demo/placement.md correctly 1`] = `
+
+`;
+
exports[`renders ./components/drawer/demo/user-profile.md correctly 1`] = `
diff --git a/components/drawer/demo/basic-left.md b/components/drawer/demo/basic-left.md
deleted file mode 100644
index 57b192f6a..000000000
--- a/components/drawer/demo/basic-left.md
+++ /dev/null
@@ -1,47 +0,0 @@
-
-#### 左侧滑出
-基础抽屉,点击触发按钮抽屉从左滑出,点击遮罩区关闭
-
-
-
-#### Left Slider
-Basic drawer.
-
-
-```html
-
-
-
- Open
-
-
- Basic Drawer
- Some contents...
- Some contents...
- Some contents...
-
-
-
-
-```
diff --git a/components/drawer/demo/index.vue b/components/drawer/demo/index.vue
index c726fb74a..15c24c5ea 100644
--- a/components/drawer/demo/index.vue
+++ b/components/drawer/demo/index.vue
@@ -1,6 +1,6 @@
+```
diff --git a/components/drawer/index.en-US.md b/components/drawer/index.en-US.md
index 47c1944dd..3cc960dda 100644
--- a/components/drawer/index.en-US.md
+++ b/components/drawer/index.en-US.md
@@ -12,10 +12,12 @@
| maskStyle | Style for Drawer's mask element. | object | {} |
| title | The title for Drawer. | string\|slot | - |
| visible | Whether the Drawer dialog is visible or not. | boolean | false |
-| width | Width of the Drawer dialog. | string\|number | 256 |
| wrapClassName | The class name of the container of the Drawer dialog. | string | - |
+| width | Width of the Drawer dialog. | string\|number | 256 |
+| height | placement is `top` or `bottom`, height of the Drawer dialog. | string\|number | - |
+| className | The class name of the container of the Drawer dialog. | string | - |
| zIndex | The `z-index` of the Drawer. | Number | 1000 |
-| placement | The placement of the Drawer. | 'left' \| 'right' | 'right'
+| placement | The placement of the Drawer. | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' |
## Methods
diff --git a/components/drawer/index.jsx b/components/drawer/index.jsx
index 5b53c97bf..c422588a7 100644
--- a/components/drawer/index.jsx
+++ b/components/drawer/index.jsx
@@ -1,6 +1,8 @@
+import classNames from 'classnames'
import VcDrawer from '../vc-drawer/src'
import PropTypes from '../_util/vue-types'
import BaseMixin from '../_util/BaseMixin'
+import Icon from '../icon'
import { getComponentFromProp, getOptionProps } from '../_util/props-util'
const Drawer = {
@@ -10,14 +12,15 @@ const Drawer = {
destroyOnClose: PropTypes.bool,
getContainer: PropTypes.any,
maskClosable: PropTypes.bool.def(true),
- mask: PropTypes.bool,
+ mask: PropTypes.bool.def(true),
maskStyle: PropTypes.object,
title: PropTypes.any,
visible: PropTypes.bool,
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).def(256),
+ height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).def(256),
zIndex: PropTypes.number,
prefixCls: PropTypes.string.def('ant-drawer'),
- placement: PropTypes.string.def('right'),
+ placement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']).def('right'),
level: PropTypes.any.def(null),
wrapClassName: PropTypes.string,
},
@@ -88,7 +91,16 @@ const Drawer = {
getDestoryOnClose () {
return this.destroyOnClose && !this.visible
},
-
+ // get drawar push width or height
+ getPushTransform (placement) {
+ if (placement === 'left' || placement === 'right') {
+ return `translateX(${placement === 'left' ? 180 : -180}px)`
+ }
+ if (placement === 'top' || placement === 'bottom') {
+ return `translateY(${placement === 'top' ? 180 : -180}px)`
+ }
+ },
+ // render drawer body dom
renderBody () {
if (this.destoryClose && !this.visible) {
return null
@@ -110,6 +122,7 @@ const Drawer = {
}
const { prefixCls, closable } = this.$props
const title = getComponentFromProp(this, 'title')
+ // is have header dom
let header
if (title) {
header = (
@@ -118,6 +131,7 @@ const Drawer = {
)
}
+ // is have closer button
let closer
if (closable) {
closer = (
@@ -127,7 +141,9 @@ const Drawer = {
aria-label='Close'
class={`${prefixCls}-close`}
>
-
+
+
+
)
}
@@ -146,31 +162,49 @@ const Drawer = {
)
},
+ getRcDrawerStyle () {
+ const { zIndex, placement, maskStyle } = this.$props
+ return this.$data._push
+ ? {
+ ...maskStyle,
+ zIndex,
+ transform: this.getPushTransform(placement),
+ }
+ : {
+ ...maskStyle,
+ zIndex,
+ }
+ },
+
},
render () {
const props = getOptionProps(this)
- const { zIndex, visible, placement, mask, wrapClassName, ...rest } = props
- const vcDrawerStyle = this.$data._push
- ? {
- zIndex,
- transform: `translateX(${placement === 'left' ? 180 : -180}px)`,
- }
- : { zIndex }
+ const { width, height, visible, placement, wrapClassName, ...rest } = props
+ const haveMask = rest.mask ? '' : 'no-mask'
+ const offsetStyle = {}
+ if (placement === 'left' || placement === 'right') {
+ offsetStyle.width = typeof width === 'number' ? `${width}px` : width
+ } else {
+ offsetStyle.height = typeof height === 'number' ? `${height}px` : height
+ }
const vcDrawerProps = {
props: {
handler: false,
- open: visible,
- showMask: mask,
- placement,
- wrapClassName,
...rest,
+ ...offsetStyle,
+ open: visible,
+ showMask: props.mask,
+ placement,
+ wrapClassName: classNames({
+ [wrapClassName]: !!wrapClassName,
+ [haveMask]: !!haveMask,
+ }),
},
on: {
maskClick: this.onMaskClick,
...this.$listeners,
},
- style: vcDrawerStyle,
-
+ style: this.getRcDrawerStyle(),
}
return (
* {
transition: transform @animation-duration-slow @ease-base-in;
@@ -28,6 +29,9 @@
&.@{dawer-prefix-cls}-open {
width: 100%;
}
+ &.@{dawer-prefix-cls}-open.no-mask {
+ width: 0%;
+ }
}
&-left {
&.@{dawer-prefix-cls}-open {
@@ -51,10 +55,17 @@
&-top,
&-bottom {
- .@{dawer-prefix-cls}-content-wrapper,
- .@{dawer-prefix-cls}-content {
+ width: 100%;
+ height: 0%;
+ .@{dawer-prefix-cls}-content-wrapper {
width: 100%;
}
+ &.@{dawer-prefix-cls}-open {
+ height: 100%;
+ }
+ &.@{dawer-prefix-cls}-open.no-mask {
+ height: 0%;
+ }
}
&-top {
&.@{dawer-prefix-cls}-open {
@@ -75,13 +86,12 @@
}
}
}
-
&.@{dawer-prefix-cls}-open {
.@{dawer-prefix-cls} {
&-mask {
opacity: 0.3;
height: 100%;
- animation: antdDrawerFadeIn @animation-duration-slow @ease-base-out;
+ animation: antdDrawerFadeIn @animation-duration-slow @ease-base-out;
transition: none;
}
}
@@ -129,12 +139,6 @@
height: 56px;
line-height: 56px;
font-size: @font-size-lg;
-
- &:before {
- content: "\e633";
- display: block;
- font-family: "anticon" !important;
- }
}
&:focus,
@@ -170,9 +174,6 @@
}
&-open {
transition: transform @animation-duration-slow @ease-base-out;
- > * {
- transition: transform @animation-duration-slow @ease-base-out;
- }
&-content {
box-shadow: @shadow-2;
}
diff --git a/components/drawer/style/index.less b/components/drawer/style/index.less
index 303b8ee83..40a49a53b 100644
--- a/components/drawer/style/index.less
+++ b/components/drawer/style/index.less
@@ -1,4 +1,3 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@import "./drawer";
-
diff --git a/components/dropdown/__tests__/__snapshots__/demo.test.js.snap b/components/dropdown/__tests__/__snapshots__/demo.test.js.snap
index ed84b871e..e1a1adcbb 100644
--- a/components/dropdown/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/dropdown/__tests__/__snapshots__/demo.test.js.snap
@@ -2,32 +2,46 @@
exports[`renders ./components/dropdown/demo/basic.md correctly 1`] = `
- Hover me
+ Hover me
+
+
`;
exports[`renders ./components/dropdown/demo/context-menu.md correctly 1`] = `Right Click on Me `;
exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
-
Dropdown
-
Dropdown
- Button
+
+
+ Button
+
+
`;
exports[`renders ./components/dropdown/demo/event.md correctly 1`] = `
- Hover me, Click menu item
+ Hover me, Click menu item
+
+
`;
exports[`renders ./components/dropdown/demo/item.md correctly 1`] = `
- Hover me
+ Hover me
+
+
`;
exports[`renders ./components/dropdown/demo/overlay-visible.md correctly 1`] = `
- Hover me
+ Hover me
+
+
`;
exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
@@ -42,10 +56,14 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
exports[`renders ./components/dropdown/demo/sub-menu.md correctly 1`] = `
- Cascading menu
+ Cascading menu
+
+
`;
exports[`renders ./components/dropdown/demo/trigger.md correctly 1`] = `
- Click me
+ Click me
+
+
`;
diff --git a/components/dropdown/demo/context-menu.md b/components/dropdown/demo/context-menu.md
index 68268dc84..f605f852c 100644
--- a/components/dropdown/demo/context-menu.md
+++ b/components/dropdown/demo/context-menu.md
@@ -1,11 +1,11 @@
#### 右键菜单
-默认是移入触发菜单,可以鼠标右键触发。
+默认是移入触发菜单,可以点击鼠标右键触发。
#### Context Menu
-The default trigger mode is `hover`, you can change it to `right click`.
+The default trigger mode is `hover`, you can change it to `contextMenu`.
```html
diff --git a/components/dropdown/demo/index.vue b/components/dropdown/demo/index.vue
index 6b581f941..7a7c62e45 100644
--- a/components/dropdown/demo/index.vue
+++ b/components/dropdown/demo/index.vue
@@ -27,6 +27,7 @@ export default {
category: 'Components',
subtitle: '下拉菜单',
type: 'Navigation',
+ zhType: '导航',
title: 'Dropdown',
render () {
return (
diff --git a/components/dropdown/dropdown-button.jsx b/components/dropdown/dropdown-button.jsx
index 4a0756293..85aa140d6 100644
--- a/components/dropdown/dropdown-button.jsx
+++ b/components/dropdown/dropdown-button.jsx
@@ -1,17 +1,19 @@
import Button from '../button'
+import buttonTypes from '../button/buttonTypes'
import { ButtonGroupProps } from '../button/button-group'
-import Icon from '../icon'
import Dropdown from './dropdown'
import PropTypes from '../_util/vue-types'
import { hasProp, getComponentFromProp } from '../_util/props-util'
import getDropdownProps from './getDropdownProps'
+const ButtonTypesProps = buttonTypes()
const DropdownProps = getDropdownProps()
const ButtonGroup = Button.Group
const DropdownButtonProps = {
...ButtonGroupProps,
...DropdownProps,
type: PropTypes.oneOf(['primary', 'ghost', 'dashed', 'danger', 'default']).def('default'),
+ htmlType: ButtonTypesProps.htmlType,
disabled: PropTypes.bool,
prefixCls: PropTypes.string.def('ant-dropdown-button'),
placement: DropdownProps.placement.def('bottomRight'),
@@ -34,7 +36,7 @@ export default {
},
render () {
const {
- type, disabled,
+ type, disabled, htmlType,
prefixCls, trigger, align,
visible, placement, getPopupContainer,
...restProps
@@ -65,6 +67,7 @@ export default {
type={type}
disabled={disabled}
onClick={this.onClick}
+ htmlType={htmlType}
>
{this.$slots.default}
diff --git a/components/dropdown/dropdown.jsx b/components/dropdown/dropdown.jsx
index ad1dee203..84b012d3b 100644
--- a/components/dropdown/dropdown.jsx
+++ b/components/dropdown/dropdown.jsx
@@ -1,11 +1,12 @@
-import RcDropdown from './src/index'
+import RcDropdown from '../vc-dropdown/src/index'
import DropdownButton from './dropdown-button'
-// import warning from '../_util/warning'
import PropTypes from '../_util/vue-types'
import { cloneElement } from '../_util/vnode'
import { getOptionProps, getPropsData } from '../_util/props-util'
import getDropdownProps from './getDropdownProps'
+import Icon from '../icon'
+
const DropdownProps = getDropdownProps()
const Dropdown = {
name: 'ADropdown',
@@ -44,11 +45,19 @@ const Dropdown = {
// menu should be focusable in dropdown defaultly
const overlayProps = overlay && getPropsData(overlay)
const { selectable = false, focusable = true } = overlayProps || {}
+
+ const expandIcon = (
+
+ )
+
const fixedModeOverlay = overlay && overlay.componentOptions ? cloneElement(overlay, {
props: {
mode: 'vertical',
selectable,
focusable,
+ expandIcon,
},
}) : overlay
const triggerActions = disabled ? [] : trigger
diff --git a/components/dropdown/style/index.less b/components/dropdown/style/index.less
index f4967b69f..ec0e955b0 100644
--- a/components/dropdown/style/index.less
+++ b/components/dropdown/style/index.less
@@ -55,6 +55,10 @@
&-submenu-popup {
position: absolute;
z-index: @zindex-dropdown;
+
+ > .@{dropdown-prefix-cls}-menu {
+ transform-origin: 0 0;
+ }
}
&-item,
@@ -117,10 +121,8 @@
.@{dropdown-prefix-cls}-menu-submenu-arrow {
position: absolute;
right: @padding-xs;
- &:after {
- font-family: "anticon" !important;
+ &-icon {
font-style: normal;
- content: "\e61f";
color: @text-color-secondary;
.iconfont-size-under-12px(10px);
}
@@ -146,7 +148,7 @@
&-submenu&-submenu-disabled .@{dropdown-prefix-cls}-menu-submenu-title {
&,
- .@{dropdown-prefix-cls}-menu-submenu-arrow:after {
+ .@{dropdown-prefix-cls}-menu-submenu-arrow-icon {
color: @disabled-color;
}
}
@@ -185,12 +187,9 @@
.@{dropdown-prefix-cls}-trigger,
.@{dropdown-prefix-cls}-link {
- .@{iconfont-css-prefix}-down {
+ > .@{iconfont-css-prefix}:not(.@{iconfont-css-prefix}-ellipsis) {
.iconfont-size-under-12px(10px);
}
- .@{iconfont-css-prefix}-ellipsis {
- text-shadow: 0 0 currentColor;
- }
}
.@{dropdown-prefix-cls}-button {
@@ -200,7 +199,7 @@
padding-left: @padding-xs;
padding-right: @padding-xs;
}
- .@{iconfont-css-prefix}-down {
+ .@{iconfont-css-prefix}:not(.@{iconfont-css-prefix}-ellipsis) {
.iconfont-size-under-12px(10px);
}
}
diff --git a/components/form/Form.jsx b/components/form/Form.jsx
index bf27ecc96..1406fb800 100755
--- a/components/form/Form.jsx
+++ b/components/form/Form.jsx
@@ -100,6 +100,8 @@ export const ValidationRule = {
// trigger?: string;
// /** 可以把 onChange 的参数转化为控件的值,例如 DatePicker 可设为:(date, dateString) => dateString */
// getValueFromEvent?: (...args: any[]) => any;
+// /** Get the component props according to field value. */
+// getValueProps?: (value: any) => any;
// /** 校验子节点值的时机 */
// validateTrigger?: string | string[];
// /** 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) */
diff --git a/components/form/FormItem.jsx b/components/form/FormItem.jsx
index dd7e1bca8..fcc13d0d0 100644
--- a/components/form/FormItem.jsx
+++ b/components/form/FormItem.jsx
@@ -6,7 +6,7 @@ import Row from '../grid/Row'
import Col, { ColProps } from '../grid/Col'
import warning from '../_util/warning'
import { FIELD_META_PROP, FIELD_DATA_PROP } from './constants'
-import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, isValidElement, getSlots, getAllChildren } from '../_util/props-util'
+import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, isValidElement, getAllChildren } from '../_util/props-util'
import getTransitionProps from '../_util/getTransitionProps'
import BaseMixin from '../_util/BaseMixin'
import { cloneElement, cloneVNodes } from '../_util/vnode'
diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap
index ffac3693e..dd62b1ad7 100644
--- a/components/form/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/form/__tests__/__snapshots__/demo.test.js.snap
@@ -4,7 +4,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = `