diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 97ac062c90..e5b55698cb 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -1,7 +1,59 @@ # Change Log +`ant-design-vue` strictly follows [Semantic Versioning 2.0.0](http://semver.org/). + +#### Release Schedule + +* Weekly release: patch version at the end of every week for routine bugfix (anytime for urgent bugfix). +* Monthly release: minor version for new features. +* Major version release is not included in this schedule for breaking change and new features. + --- +## 1.3.0 +`2019-01-12` + +- 🎉 🎉 🎉 Publish the vscode plugin [ant-design-vue-helper](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) + +### Component features and styles are synchronized to antd version 3.11.6. +1.3.0 brings two new Components, a lot of exciting changes and new features. + +- 🔥 Added a new component [Comment](https://vuecomponent.github.io/ant-design-vue/components/comment/)。 +- 🔥 dded a new component [ConfigProvider](https://vuecomponent.github.io/ant-design-vue/components/config-provider/) for user to customize some global setting. + +Component Fixes / Enhancements: + +- 🌟 Avatar Added `srcSet` prop that is a list of sources to use for different screen resolutions. +- 🌟 Notification Added `onClick` prop that is called when the notification is clicked. +- Transfer + - 🌟 Added `search` event that is executed when search field are changed and deprecated `searchChange` event. + - 🌟 Added `disabled` prop that whether disable transfer. +- 🌟 Refactor Badge, support `count` as custom component. +- Slider + - 🌟 Added `tooltipVisible` prop that whether Tooltip will always show. + - 🌟 Optimize the focus effect + - 🐞 Fix tooltip does not display the problem when focus through the keyboard tab. + - 🐞 Fix the hidden switch problem of Tooltip while dragging. +- Calendar + - 🌟 Support multiple date format. + - 🌟 showSearch added `limit` prop that support limit filtered item count. +- Table + - 🌟 Added `expandIcon` prop that custom the default expand icon. + - 🌟 customCell added `index` prop. +- Select + - 🌟 Added `removeIcon`、`clearIcon`、`menuItemSelectedIcon` prop,allow setting `remove`、`clear`、`menuItemSelected` custom icons. + - 🌟 Added `dropdownRender` prop that custom dropdown content. + - 🌟 Added `loading` prop that indicate loading state. +- 🌟 Optimize the display of the Button when it contains an Icon. +- ⚡️ Refactor Tag component with less code and better performance. +- 💄 Added `title` prop that Menu.Item support tooltip title when collapsed. +- 💄 Chore Card header and loading UI. +- 💄 Optimized Spin wrapper styles and improve performance slightly. +- 🐞 Fix TextArea use resize observer to check textarea size. +- 🐞 Fix Tooltip in the disabled state, the style error problem.[#389](https://github.com/vueComponent/ant-design-vue/issues/389) +- 🐞 Fix some component TypeScript definitions. + + ## 1.2.5 `2019-01-06` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 0f77d5d23c..14339afe1f 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -1,7 +1,59 @@ # 更新日志 +`ant-design-vue` 严格遵循 [Semantic Versioning 2.0.0](http://semver.org/lang/zh-CN/) 语义化版本规范。 + +#### 发布周期 + +* 修订版本号:每周末会进行日常 bugfix 更新。(如果有紧急的 bugfix,则任何时候都可发布) +* 次版本号:带有新特性的向下兼容的版本。 +* 主版本号:含有破坏性更新和新特性,不在发布周期内。 + --- +## 1.3.0 +`2019-01-12` + +- 🎉 🎉 🎉 发布 vscode 插件 [ant-design-vue-helper](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) + +### 组件功能和样式同步到 antd 3.11.6 版本。 +1.3.0 版本带来了两个新组件,还有很多激动人心的变化和新特性。 + +- 🔥 增加了一个新组件 [Comment](https://vuecomponent.github.io/ant-design-vue/components/comment-cn/)。 +- 🔥 增加了一个新组件 [ConfigProvider](https://vuecomponent.github.io/ant-design-vue/components/config-provider-cn/) 为组件提供统一的全局化配置。 + +组件修复/功能增强: + +- 🌟 Avatar 组件增加 `srcSet` 属性,用于设置图片类头像响应式资源地址。 +- 🌟 Notification 组件增加 `onClick` 属性,点击通知时触发的回调函数。 +- Transfer + - 🌟 增加 `search` 事件,搜索框内容时改变时的回调函数,并废弃 `searchChange` 事件。 + - 🌟 增加 `disabled` 属性,用于禁用搜索框。 +- 🌟 Badge 进行了重构,`count` 支持自定义组件。 +- Slider + - 🌟 增加 `tooltipVisible` 属性,用于 Tooltip 是否始终显示。 + - 🌟 优化focus效果 + - 🐞 修复键盘tab键聚焦时,Tooltip不显示问题。 + - 🐞 修复拖动时Tooltip不停的显隐切换问题。 +- Calendar + - 🌟 支持多种时间格式。 + - 🌟 showSearch 方法增加 `limit` 参数,用于限制搜索结果展示数量。 +- Table + - 🌟 增加 `expandIcon` 属性,用于自定义表格展开图标。 + - 🌟 customCell 方法增加 `index` 参数。 +- Select + - 🌟 增加 `removeIcon`、`clearIcon`、`menuItemSelectedIcon` 属性,用于自定义删除、清空、选中的图标。 + - 🌟 增加 `dropdownRender` 属性, 用于自定义下拉框内容。 + - 🌟 增加 `loading` 属性, 用于展示加载中状态。 +- 🌟 优化 Button 在含有Icon时的显示效果。 +- ⚡️ 重构 Tag 组件,简化代码并提升性能。 +- 💄 Menu.Item 组件增加 `title` 属性,用于在收缩时展示的悬浮标题。 +- 💄 微调 Card 头部和加载中的样式细节。 +- 💄 优化 Spin 样式并略微提升了切换状态的性能。 +- 🐞 修复 TextArea 组件高度不能自适应问题。 +- 🐞 修复 Tooltip 在disabled状态下Button中,样式错误问题。[#389](https://github.com/vueComponent/ant-design-vue/issues/389) +- 🐞 修复一些组件 TypeScript 定义。 + + ## 1.2.5 `2019-01-06` diff --git a/components/_util/BaseMixin.js b/components/_util/BaseMixin.js index 1897d3cfec..f01a6b5e3e 100644 --- a/components/_util/BaseMixin.js +++ b/components/_util/BaseMixin.js @@ -1,21 +1,21 @@ export default { - directives: { - 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) - }, - }, - }, + // directives: { + // 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) + // }, + // }, + // }, methods: { setState (state, callback) { - const newState = typeof state === 'function' ? state(this.$data) : state + const newState = typeof state === 'function' ? state(this.$data, this.$props) : state // if (this.getDerivedStateFromProps) { // Object.assign(newState, this.getDerivedStateFromProps(getOptionProps(this), { ...this.$data, ...newState }, true) || {}) // } diff --git a/components/_util/Dom/addEventListener.js b/components/_util/Dom/addEventListener.js index 2c4c3eec38..4ea8998c87 100644 --- a/components/_util/Dom/addEventListener.js +++ b/components/_util/Dom/addEventListener.js @@ -1,5 +1,5 @@ import addDOMEventListener from 'add-dom-event-listener' -export default function addEventListenerWrap (target, eventType, cb) { - return addDOMEventListener(target, eventType, cb) +export default function addEventListenerWrap (target, eventType, cb, option) { + return addDOMEventListener(target, eventType, cb, option) } diff --git a/components/_util/props-util.js b/components/_util/props-util.js index 996b6f8a6d..65856cae9f 100644 --- a/components/_util/props-util.js +++ b/components/_util/props-util.js @@ -52,9 +52,11 @@ const getSlots = (ele) => { const children = ele.children || componentOptions.children || [] const slots = {} children.forEach(child => { - const name = (child.data && child.data.slot) || 'default' - slots[name] = slots[name] || [] - slots[name].push(child) + if (!isEmptyElement(child)) { + const name = (child.data && child.data.slot) || 'default' + slots[name] = slots[name] || [] + slots[name].push(child) + } }) return slots } @@ -215,12 +217,12 @@ export function getComponentName (opts) { return opts && (opts.Ctor.options.name || opts.tag) } -export function isEmptyElement (ele) { - return !(ele.tag || ele.text.trim() !== '') +export function isEmptyElement (c) { + return !(c.tag || (c.text && c.text.trim() !== '')) } export function filterEmpty (children = []) { - return children.filter(c => c.tag || (c.text && c.text.trim() !== '')) + return children.filter(c => !isEmptyElement(c)) } const initDefaultProps = (propTypes, defaultProps) => { Object.keys(defaultProps).forEach(k => { @@ -252,7 +254,11 @@ export function mergeProps () { } function isValidElement (element) { - return element && element.context && element.context._isVue + return element && + typeof element === 'object' && + 'componentOptions' in element && + 'context' in element && + element.tag !== undefined // remove text node } export { diff --git a/components/_util/wave.jsx b/components/_util/wave.jsx index ac262e1569..396d5d5bc2 100644 --- a/components/_util/wave.jsx +++ b/components/_util/wave.jsx @@ -117,7 +117,7 @@ export default { }, resetEffect (node) { - if (!node || node === this.extraNode) { + if (!node || node === this.extraNode || !(node instanceof Element)) { return } const { insertExtraNode } = this.$props diff --git a/components/affix/index.jsx b/components/affix/index.jsx index a9fb0b25b9..56df9af4ff 100644 --- a/components/affix/index.jsx +++ b/components/affix/index.jsx @@ -83,6 +83,8 @@ const Affix = { // Wait for parent component ref has its value this.timeout = setTimeout(() => { this.setTargetEventListeners(target) + // Mock Event object. + this.updatePosition({}) }) }, watch: { diff --git a/components/affix/style/index.less b/components/affix/style/index.less index cd61d1ed08..9f19860e55 100644 --- a/components/affix/style/index.less +++ b/components/affix/style/index.less @@ -1,4 +1,4 @@ -@import "../../style/themes/default"; +@import '../../style/themes/default'; .@{ant-prefix}-affix { position: fixed; diff --git a/components/alert/__tests__/__snapshots__/demo.test.js.snap b/components/alert/__tests__/__snapshots__/demo.test.js.snap index b42763a71c..c053c36245 100644 --- a/components/alert/__tests__/__snapshots__/demo.test.js.snap +++ b/components/alert/__tests__/__snapshots__/demo.test.js.snap @@ -5,7 +5,7 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
Warning text

-
Very long warning text warning text text text text text text text
-
Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text -
Error TextError Description Error Description Error Description Error Description Error Description Error Description
`; -exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
Info TextClose Now
`; +exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
Info TextClose Now
`; exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
@@ -92,7 +92,7 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = ` exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
-
Alert Message Text
diff --git a/components/alert/index.jsx b/components/alert/index.jsx index a02b244a15..53ad294ea4 100644 --- a/components/alert/index.jsx +++ b/components/alert/index.jsx @@ -103,19 +103,20 @@ const Alert = { } } + // closeable when closeText is assigned + if (closeText) { + closable = true + } + const alertCls = classNames(prefixCls, { [`${prefixCls}-${type}`]: true, [`${prefixCls}-close`]: !closing, [`${prefixCls}-with-description`]: !!description, [`${prefixCls}-no-icon`]: !showIcon, [`${prefixCls}-banner`]: !!banner, + [`${prefixCls}-closable`]: closable, }) - // closeable when closeText is assigned - if (closeText) { - closable = true - } - const closeIcon = closable ? ( {closeText || } diff --git a/components/alert/style/index.less b/components/alert/style/index.less index a876d69211..180e9cf2fe 100644 --- a/components/alert/style/index.less +++ b/components/alert/style/index.less @@ -1,11 +1,12 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@alert-prefix-cls: ~"@{ant-prefix}-alert"; +@alert-prefix-cls: ~'@{ant-prefix}-alert'; @alert-message-color: @heading-color; @alert-text-color: @text-color; @alert-close-color: @text-color-secondary; +@alert-close-hover-color: #404040; .@{alert-prefix-cls} { .reset-component; @@ -17,6 +18,10 @@ padding: 8px 15px; } + &&-closable { + padding-right: 30px; + } + &-icon { top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2; left: 16px; @@ -72,9 +77,9 @@ .@{iconfont-css-prefix}-close { color: @alert-close-color; - transition: color .3s; + transition: color 0.3s; &:hover { - color: #404040; + color: @alert-close-hover-color; } } } @@ -127,12 +132,12 @@ margin: 0; padding-top: 0; padding-bottom: 0; - transition: all .3s @ease-in-out-circ; + transition: all 0.3s @ease-in-out-circ; transform-origin: 50% 0; } &-slide-up-leave { - animation: antAlertSlideUpOut .3s @ease-in-out-circ; + animation: antAlertSlideUpOut 0.3s @ease-in-out-circ; animation-fill-mode: both; } diff --git a/components/anchor/style/index.less b/components/anchor/style/index.less index 3a5ddec9aa..ec2386b821 100644 --- a/components/anchor/style/index.less +++ b/components/anchor/style/index.less @@ -1,5 +1,5 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; @anchor-border-width: 2px; @@ -38,7 +38,7 @@ border: 2px solid @primary-color; background-color: @component-background; left: 50%; - transition: top .3s ease-in-out; + transition: top 0.3s ease-in-out; transform: translateX(-50%); &.visible { display: inline-block; @@ -57,7 +57,7 @@ &-title { display: block; position: relative; - transition: all .3s; + transition: all 0.3s; color: @text-color; white-space: nowrap; overflow: hidden; diff --git a/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap b/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap index dc5a08f8e0..5344c17817 100644 --- a/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap +++ b/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap @@ -2,15 +2,15 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = ` `; @@ -18,15 +18,15 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = ` exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1`] = `
@@ -34,44 +34,44 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1 exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = ` `; exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly 1`] = ` `; exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = ` `; @@ -79,15 +79,15 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = ` exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly 1`] = `
diff --git a/components/auto-complete/style/index.less b/components/auto-complete/style/index.less index 74e45c21c6..4c9dc25e3f 100644 --- a/components/auto-complete/style/index.less +++ b/components/auto-complete/style/index.less @@ -1,10 +1,10 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; -@import "../../input/style/mixin"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; +@import '../../input/style/mixin'; -@input-prefix-cls: ~"@{ant-prefix}-input"; -@select-prefix-cls: ~"@{ant-prefix}-select"; -@autocomplete-prefix-cls: ~"@{select-prefix-cls}-auto-complete"; +@input-prefix-cls: ~'@{ant-prefix}-input'; +@select-prefix-cls: ~'@{ant-prefix}-select'; +@autocomplete-prefix-cls: ~'@{select-prefix-cls}-auto-complete'; .@{autocomplete-prefix-cls} { .reset-component; diff --git a/components/avatar/Avatar.jsx b/components/avatar/Avatar.jsx index 5aedd58d8e..baf1bafd77 100644 --- a/components/avatar/Avatar.jsx +++ b/components/avatar/Avatar.jsx @@ -19,6 +19,8 @@ export default { default: 'default', }, src: String, + /** Srcset of image avatar */ + srcSet: String, icon: String, alt: String, loadError: Function, @@ -71,7 +73,7 @@ export default { }, render () { const { - prefixCls, shape, size, src, icon, alt, + prefixCls, shape, size, src, icon, alt, srcSet, } = this.$props const { isImgExist, scale } = this.$data @@ -101,6 +103,7 @@ export default { children = ( {alt} diff --git a/components/avatar/__tests__/__snapshots__/demo.test.js.snap b/components/avatar/__tests__/__snapshots__/demo.test.js.snap index a6787108dc..5b62664483 100644 --- a/components/avatar/__tests__/__snapshots__/demo.test.js.snap +++ b/components/avatar/__tests__/__snapshots__/demo.test.js.snap @@ -1,6 +1,6 @@ // 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`] = `
diff --git a/components/avatar/index.en-US.md b/components/avatar/index.en-US.md index 9e33ea2a65..8ccc83caa7 100644 --- a/components/avatar/index.en-US.md +++ b/components/avatar/index.en-US.md @@ -6,6 +6,7 @@ | shape | the shape of avatar | `circle` \| `square` | `circle` | | size | the size of the avatar | number \| string: `large` `small` `default` | `default` | | src | the address of the image for an image avatar | string | - | +| srcSet | a list of sources to use for different screen resolutions | string | - | | alt | This attribute defines the alternative text describing the image | string | - | | loadError | handler when img load error,return false to prevent default fallback behavior | () => boolean | - | diff --git a/components/avatar/index.zh-CN.md b/components/avatar/index.zh-CN.md index 07d4c16dd3..16b81f4bc1 100644 --- a/components/avatar/index.zh-CN.md +++ b/components/avatar/index.zh-CN.md @@ -6,6 +6,7 @@ | shape | 指定头像的形状 | Enum{ 'circle', 'square' } | `circle` | | size | 设置头像的大小 | number \| Enum{ 'large', 'small', 'default' } | `default` | | src | 图片类头像的资源地址 | string | - | +| srcSet | 设置图片类头像响应式资源地址 | string | - | | alt | 图像无法显示时的替代文本 | string | - | | loadError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为 | () => boolean | - | diff --git a/components/avatar/style/index.less b/components/avatar/style/index.less index da52c414dc..8283ff76dc 100644 --- a/components/avatar/style/index.less +++ b/components/avatar/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@avatar-prefix-cls: ~"@{ant-prefix}-avatar"; +@avatar-prefix-cls: ~'@{ant-prefix}-avatar'; .@{avatar-prefix-cls} { .reset-component; @@ -45,10 +45,6 @@ line-height: @size; border-radius: 50%; - & > * { - line-height: @size; - } - &-string { position: absolute; left: 50%; diff --git a/components/back-top/__tests__/index.test.js b/components/back-top/__tests__/index.test.js index 803b7d5e67..caddee20f0 100644 --- a/components/back-top/__tests__/index.test.js +++ b/components/back-top/__tests__/index.test.js @@ -2,15 +2,7 @@ import { mount } from '@vue/test-utils' import BackTop from '..' describe('BackTop', () => { - beforeAll(() => { - jest.useFakeTimers() - }) - - afterAll(() => { - jest.useRealTimers() - }) - - it('should scroll to top after click it', () => { + it('should scroll to top after click it', async () => { const wrapper = mount(BackTop, { propsData: { visibilityHeight: -1, @@ -19,9 +11,9 @@ describe('BackTop', () => { document.documentElement.scrollTop = 400 // trigger scroll manually wrapper.vm.handleScroll() - jest.runAllTimers() + await new Promise(resolve => setTimeout(resolve, 0)) wrapper.find('.ant-back-top').trigger('click') - jest.runAllTimers() + await new Promise(resolve => setTimeout(resolve, 1000)) expect(Math.abs(Math.round(document.documentElement.scrollTop))).toBe(0) }) }) diff --git a/components/back-top/style/index.less b/components/back-top/style/index.less index 27d59ff6df..c1a0d29b23 100644 --- a/components/back-top/style/index.less +++ b/components/back-top/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@backtop-prefix-cls: ~"@{ant-prefix}-back-top"; +@backtop-prefix-cls: ~'@{ant-prefix}-back-top'; .@{backtop-prefix-cls} { .reset-component; @@ -20,12 +20,12 @@ background-color: @back-top-bg; color: @back-top-color; text-align: center; - transition: all .3s @ease-in-out; + transition: all 0.3s @ease-in-out; overflow: hidden; &:hover { background-color: @back-top-hover-bg; - transition: all .3s @ease-in-out; + transition: all 0.3s @ease-in-out; } } @@ -33,7 +33,8 @@ margin: 12px auto; width: 14px; height: 16px; - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAoCAYAAACWwljjAAAABGdBTUEAALGPC/xhBQAAAbtJREFUWAntmMtKw0AUhhMvS5cuxILgQlRUpIggIoKIIoigG1eC+AA+jo+i6FIXBfeuXIgoeKVeitVWJX5HWhhDksnUpp3FDPyZk3Nm5nycmZKkXhAEOXSA3lG7muTeRzmfy6HneUvIhnYkQK+Q9NhAA0Opg0vBEhjBKHiyb8iGMyQMOYuK41BcBSypAL+MYXSKjtFAW7EAGEO3qN4uMQbbAkXiSfRQJ1H6a+yhlkKRcAoVFYiweYNjtCVQJJpBz2GCiPt7fBOZQpFgDpUikse5HgnkM4Fi4QX0Fpc5wf9EbLqpUCy4jMoJSXWhFwbMNgWKhVbRhy5jirhs9fy/oFhgHVVTJEs7RLZ8sSEoJm6iz7SZDMbJ+/OKERQTttCXQRLToRUmrKWCYuA2+jbN0MB4OQobYShfdTCgn/sL1K36M7TLrN3n+758aPy2rrpR6+/od5E8tf/A1uLS9aId5T7J3CNYihkQ4D9PiMdMC7mp4rjB9kjFjZp8BlnVHJBuO1yFXIV0FdDF3RlyFdJVQBdv5AxVdIsq8apiZ2PyYO1EVykesGfZEESsCkweyR8MUW+V8uJ1gkYipmpdP1pm2aJVPEGzAAAAAElFTkSuQmCC) ~"100%/100%" no-repeat; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAoCAYAAACWwljjAAAABGdBTUEAALGPC/xhBQAAAbtJREFUWAntmMtKw0AUhhMvS5cuxILgQlRUpIggIoKIIoigG1eC+AA+jo+i6FIXBfeuXIgoeKVeitVWJX5HWhhDksnUpp3FDPyZk3Nm5nycmZKkXhAEOXSA3lG7muTeRzmfy6HneUvIhnYkQK+Q9NhAA0Opg0vBEhjBKHiyb8iGMyQMOYuK41BcBSypAL+MYXSKjtFAW7EAGEO3qN4uMQbbAkXiSfRQJ1H6a+yhlkKRcAoVFYiweYNjtCVQJJpBz2GCiPt7fBOZQpFgDpUikse5HgnkM4Fi4QX0Fpc5wf9EbLqpUCy4jMoJSXWhFwbMNgWKhVbRhy5jirhs9fy/oFhgHVVTJEs7RLZ8sSEoJm6iz7SZDMbJ+/OKERQTttCXQRLToRUmrKWCYuA2+jbN0MB4OQobYShfdTCgn/sL1K36M7TLrN3n+758aPy2rrpR6+/od5E8tf/A1uLS9aId5T7J3CNYihkQ4D9PiMdMC7mp4rjB9kjFjZp8BlnVHJBuO1yFXIV0FdDF3RlyFdJVQBdv5AxVdIsq8apiZ2PyYO1EVykesGfZEESsCkweyR8MUW+V8uJ1gkYipmpdP1pm2aJVPEGzAAAAAElFTkSuQmCC) + ~'100%/100%' no-repeat; } } diff --git a/components/badge/Badge.jsx b/components/badge/Badge.jsx index e9c9d5f256..c1c5775995 100644 --- a/components/badge/Badge.jsx +++ b/components/badge/Badge.jsx @@ -2,12 +2,14 @@ import PropTypes from '../_util/vue-types' import ScrollNumber from './ScrollNumber' import classNames from 'classnames' -import { initDefaultProps, filterEmpty } from '../_util/props-util' +import { initDefaultProps, filterEmpty, getComponentFromProp } from '../_util/props-util' +import { cloneElement } from '../_util/vnode' import getTransitionProps from '../_util/getTransitionProps' +import isNumeric from '../_util/isNumeric' export const BadgeProps = { /** Number to show in badge */ - count: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]), + count: PropTypes.any, showZero: PropTypes.bool, /** Max count to show */ overflowCount: PropTypes.number, @@ -27,85 +29,162 @@ export default { props: initDefaultProps(BadgeProps, { prefixCls: 'ant-badge', scrollNumberPrefixCls: 'ant-scroll-number', - count: null, showZero: false, dot: false, overflowCount: 99, }), + methods: { + getBadgeClassName () { + const { prefixCls, status } = this.$props + const children = filterEmpty(this.$slots.default) + return classNames(prefixCls, { + [`${prefixCls}-status`]: !!status, + [`${prefixCls}-not-a-wrapper`]: !children.length, + }) + }, + + isZero () { + const numberedDispayCount = this.getNumberedDispayCount() + return numberedDispayCount === '0' || numberedDispayCount === 0 + }, + + isDot () { + const { dot, status } = this.$props + const isZero = this.isZero() + return (dot && !isZero) || status + }, + + isHidden () { + const { showZero } = this.$props + const displayCount = this.getDispayCount() + const isZero = this.isZero() + const isDot = this.isDot() + const isEmpty = displayCount === null || displayCount === undefined || displayCount === '' + return (isEmpty || (isZero && !showZero)) && !isDot + }, + + getNumberedDispayCount () { + const { overflowCount } = this.$props + const count = this.badgeCount + const displayCount = + count > overflowCount ? `${overflowCount}+` : count + return displayCount + }, + + getDispayCount () { + const isDot = this.isDot() + // dot mode don't need count + if (isDot) { + return '' + } + return this.getNumberedDispayCount() + }, + + getScollNumberTitle () { + const { title } = this.$props + const count = this.badgeCount + if (title) { + return title + } + return typeof count === 'string' || typeof count === 'number' ? count : undefined + }, + + getStyleWithOffset () { + const { offset, numberStyle } = this.$props + return offset + ? { + right: `${-parseInt(offset[0], 10)}px`, + marginTop: isNumeric(offset[1]) ? `${offset[1]}px` : offset[1], + ...numberStyle, + } + : numberStyle + }, + + renderStatusText () { + const { prefixCls, text } = this.$props + const hidden = this.isHidden() + return hidden || !text ? null : {text} + }, + + renderDispayComponent () { + const count = this.badgeCount + const customNode = count + if (!customNode || typeof customNode !== 'object') { + return undefined + } + return cloneElement(customNode, { + style: this.getStyleWithOffset(), + }) + }, + + renderBadgeNumber () { + const { prefixCls, scrollNumberPrefixCls, status } = this.$props + const count = this.badgeCount + const displayCount = this.getDispayCount() + const isDot = this.isDot() + const hidden = this.isHidden() + + const scrollNumberCls = { + [`${prefixCls}-dot`]: isDot, + [`${prefixCls}-count`]: !isDot, + [`${prefixCls}-multiple-words`]: + !isDot && count && count.toString && count.toString().length > 1, + [`${prefixCls}-status-${status}`]: !!status, + } + + return hidden ? null : ( + }> + title={this.getScollNumberTitle()} + style={this.getStyleWithOffset()} + key='scrollNumber' + /> + ) + }, + }, render () { const { - count, - showZero, prefixCls, - scrollNumberPrefixCls, - overflowCount, - dot, status, text, - offset, $slots, - numberStyle, - title, } = this - let displayCount = count > overflowCount ? `${overflowCount}+` : count - const isZero = displayCount === '0' || displayCount === 0 - const isDot = (dot && !isZero) || status - // dot mode don't need count - if (isDot) { - displayCount = '' - } const children = filterEmpty($slots.default) - const isEmpty = displayCount === null || displayCount === undefined || displayCount === '' - const hidden = (isEmpty || (isZero && !showZero)) && !isDot + let count = getComponentFromProp(this, 'count') + if (Array.isArray(count)) { + count = count[0] + } + this.badgeCount = count + const scrollNumber = this.renderBadgeNumber() + const statusText = this.renderStatusText() const statusCls = classNames({ [`${prefixCls}-status-dot`]: !!status, [`${prefixCls}-status-${status}`]: !!status, }) - const scrollNumberCls = classNames({ - [`${prefixCls}-dot`]: isDot, - [`${prefixCls}-count`]: !isDot, - [`${prefixCls}-multiple-words`]: !isDot && count && count.toString && count.toString().length > 1, - [`${prefixCls}-status-${status}`]: !!status, - }) - const badgeCls = classNames(prefixCls, { - [`${prefixCls}-status`]: !!status, - [`${prefixCls}-not-a-wrapper`]: !children.length, - }) - const styleWithOffset = offset ? { - right: -parseInt(offset[0], 10), - marginTop: typeof offset[1] === 'number' ? `${offset[1]}px` : offset[1], - ...numberStyle, - } : numberStyle - // + // if (!children.length && status) { return ( - + {text} ) } - const scrollNumber = hidden ? null : ( - - ) - - const statusText = (hidden || !text) ? null : ( - {text} - ) const transitionProps = getTransitionProps(children.length ? `${prefixCls}-zoom` : '') - return ( + return ( {children} {scrollNumber} diff --git a/components/badge/ScrollNumber.jsx b/components/badge/ScrollNumber.jsx index 341c1e1c79..4ed3ff0608 100644 --- a/components/badge/ScrollNumber.jsx +++ b/components/badge/ScrollNumber.jsx @@ -1,8 +1,9 @@ - +import classNames from 'classnames' import PropTypes from '../_util/vue-types' import BaseMixin from '../_util/BaseMixin' import { getStyle } from '../_util/props-util' import omit from 'omit.js' +import { cloneElement } from '../_util/vnode' function getNumberArray (num) { return num @@ -14,9 +15,11 @@ function getNumberArray (num) { const ScrollNumberProps = { prefixCls: PropTypes.string.def('ant-scroll-number'), - count: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]).def(null), + count: PropTypes.any, component: PropTypes.string, title: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]), + displayComponent: PropTypes.any, + className: PropTypes.object, } export default { @@ -105,13 +108,19 @@ export default { }, render () { - const { prefixCls, title, component: Tag = 'sup' } = this + const { prefixCls, title, component: Tag = 'sup', displayComponent, className } = this + if (displayComponent) { + return cloneElement(displayComponent, { + class: `${prefixCls}-custom-component`, + }) + } const style = getStyle(this, true) // fix https://fb.me/react-unknown-prop const restProps = omit(this.$props, [ 'count', 'component', 'prefixCls', + 'displayComponent', ]) const newProps = { props: { @@ -120,8 +129,8 @@ export default { attrs: { title, }, - class: prefixCls, style, + class: classNames(prefixCls, className), } // allow specify the border // mock border-color by box-shadow for compatible with old usage: @@ -129,6 +138,7 @@ export default { if (style && style.borderColor) { newProps.style.boxShadow = `0 0 0 1px ${style.borderColor} inset` } + return ( { this.renderNumberElement()} diff --git a/components/badge/__tests__/__snapshots__/demo.test.js.snap b/components/badge/__tests__/__snapshots__/demo.test.js.snap index 6e4863e278..a2c8a7a5ab 100644 --- a/components/badge/__tests__/__snapshots__/demo.test.js.snap +++ b/components/badge/__tests__/__snapshots__/demo.test.js.snap @@ -1,28 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -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

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/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

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/change.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

+

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

`; +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

`; -exports[`renders ./components/badge/demo/no-wrapper.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

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

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

99+
`; +exports[`renders ./components/badge/demo/no-wrapper.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

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

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

99+
`; -exports[`renders ./components/badge/demo/overflow.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

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

99+ 10+ 999+
`; +exports[`renders ./components/badge/demo/overflow.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

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

99+ 10+ 999+
`; exports[`renders ./components/badge/demo/status.md correctly 1`] = `

Success
Error
Default
Processing
warning
`; -exports[`renders ./components/badge/demo/title.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/title.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/__tests__/__snapshots__/index.test.js.snap b/components/badge/__tests__/__snapshots__/index.test.js.snap index 5d8f7e0d04..23c9ae8c02 100644 --- a/components/badge/__tests__/__snapshots__/index.test.js.snap +++ b/components/badge/__tests__/__snapshots__/index.test.js.snap @@ -1,13 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Badge should be compatible with borderColor style 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[`Badge should be compatible with borderColor style 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[`Badge should render when count is changed 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

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[`Badge should render when count is changed 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

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[`Badge should render when count is changed 2`] = `

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

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[`Badge should render when count is changed 2`] = `

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

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[`Badge should render when count is changed 3`] = `

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

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[`Badge should render when count is changed 3`] = `

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

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[`Badge should render when count is changed 4`] = `

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

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[`Badge should render when count is changed 4`] = `

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

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[`Badge should render when count is changed 5`] = `

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[`Badge should render when count is changed 5`] = `

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[`Badge should support offset when count is a ReactNode 1`] = ``; diff --git a/components/badge/__tests__/index.test.js b/components/badge/__tests__/index.test.js index ecc4e262ff..0c8577b4d7 100644 --- a/components/badge/__tests__/index.test.js +++ b/components/badge/__tests__/index.test.js @@ -85,4 +85,18 @@ describe('Badge', () => { expect(wrapper.html()).toMatchSnapshot() }) + + // https://github.com/ant-design/ant-design/issues/13694 + it('should support offset when count is a ReactNode', () => { + const wrapper = mount({ + render () { + return ( + } offset={[10, 20]}> + + + ) + }, + }) + expect(wrapper.html()).toMatchSnapshot() + }) }) diff --git a/components/badge/demo/basic.md b/components/badge/demo/basic.md index f14ddd2211..cea87fe5af 100644 --- a/components/badge/demo/basic.md +++ b/components/badge/demo/basic.md @@ -17,6 +17,10 @@ Simplest Usage. Badge will be hidden when `count` is `0`, but we can use `showZe + + + +
``` diff --git a/components/badge/index.en_US.md b/components/badge/index.en_US.md index f86f2de85b..60f3f8714e 100644 --- a/components/badge/index.en_US.md +++ b/components/badge/index.en_US.md @@ -12,7 +12,7 @@ | Property | Description | Type | Default | | -------- | ----------- | ---- | ------- | -| count | Number to show in badge | number\|string | | +| count | Number to show in badge | number\|string \| slot | | | dot | Whether to display a red dot instead of `count` | boolean | `false` | | offset | set offset of the badge dot, like [x, y] | [number\|string, number\|string] | - | | overflowCount | Max count to show | number | 99 | diff --git a/components/badge/index.zh-CN.md b/components/badge/index.zh-CN.md index f03075a6d2..bc9bc5ffb0 100644 --- a/components/badge/index.zh-CN.md +++ b/components/badge/index.zh-CN.md @@ -13,7 +13,7 @@ | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| count | 展示的数字,大于 overflowCount 时显示为 `${overflowCount}+`,为 0 时隐藏 | number\|string | | +| count | 展示的数字,大于 overflowCount 时显示为 `${overflowCount}+`,为 0 时隐藏 | number \| string \| slot | | | dot | 不展示数字,只有一个小红点 | boolean | false | | offset | 设置状态点的位置偏移,格式为 [x, y] | [number\|string, number\|string] | - | | overflowCount | 展示封顶的数字值 | number | 99 | diff --git a/components/badge/style/index.less b/components/badge/style/index.less index 78616faa5f..81ef4bc976 100644 --- a/components/badge/style/index.less +++ b/components/badge/style/index.less @@ -1,8 +1,8 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@badge-prefix-cls: ~"@{ant-prefix}-badge"; -@number-prefix-cls: ~"@{ant-prefix}-scroll-number"; +@badge-prefix-cls: ~'@{ant-prefix}-badge'; +@number-prefix-cls: ~'@{ant-prefix}-scroll-number'; .@{badge-prefix-cls} { .reset-component; @@ -47,13 +47,18 @@ } &-count, - &-dot { + &-dot, + .@{number-prefix-cls}-custom-component { position: absolute; right: 0; transform: translateX(50%); transform-origin: 100%; } + .@{number-prefix-cls}-custom-component { + transform: translate(50%, -50%); + } + &-status { line-height: inherit; vertical-align: baseline; @@ -81,7 +86,7 @@ height: 100%; border-radius: 50%; border: 1px solid @processing-color; - content: ""; + content: ''; animation: antStatusProcessing 1.2s infinite ease-in-out; } } @@ -103,12 +108,12 @@ &-zoom-appear, &-zoom-enter { - animation: antZoomBadgeIn .3s @ease-out-back; + animation: antZoomBadgeIn 0.3s @ease-out-back; animation-fill-mode: both; } &-zoom-leave { - animation: antZoomBadgeOut .3s @ease-in-back; + animation: antZoomBadgeOut 0.3s @ease-in-back; animation-fill-mode: both; } @@ -142,7 +147,7 @@ overflow: hidden; &-only { display: inline-block; - transition: all .3s @ease-in-out; + transition: all 0.3s @ease-in-out; height: @badge-height; > p { height: @badge-height; diff --git a/components/breadcrumb/style/index.less b/components/breadcrumb/style/index.less index 2d73ab20c7..30caa83444 100644 --- a/components/breadcrumb/style/index.less +++ b/components/breadcrumb/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@breadcrumb-prefix-cls: ~"@{ant-prefix}-breadcrumb"; +@breadcrumb-prefix-cls: ~'@{ant-prefix}-breadcrumb'; .@{breadcrumb-prefix-cls} { .reset-component; @@ -14,7 +14,7 @@ a { color: @breadcrumb-link-color; - transition: color .3s; + transition: color 0.3s; &:hover { color: @breadcrumb-link-color-hover; } diff --git a/components/button/__tests__/__snapshots__/demo.test.js.snap b/components/button/__tests__/__snapshots__/demo.test.js.snap index 4dff6fe2a7..c7ba670e2d 100644 --- a/components/button/__tests__/__snapshots__/demo.test.js.snap +++ b/components/button/__tests__/__snapshots__/demo.test.js.snap @@ -8,14 +8,12 @@ exports[`renders ./components/button/demo/button-group.md correctly 1`] = `

Basic

-
+

With Icon



-
+


+
`; @@ -70,8 +68,7 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = ` `; exports[`renders ./components/button/demo/multiple.md correctly 1`] = ` -
`; @@ -85,9 +82,7 @@ exports[`renders ./components/button/demo/size.md correctly 1`] = ` Download
diff --git a/components/button/__tests__/__snapshots__/index.test.js.snap b/components/button/__tests__/__snapshots__/index.test.js.snap index 834e923540..d3cb7ff8d0 100644 --- a/components/button/__tests__/__snapshots__/index.test.js.snap +++ b/components/button/__tests__/__snapshots__/index.test.js.snap @@ -15,7 +15,7 @@ exports[`Button renders Chinese characters correctly 1`] = ` exports[`Button renders Chinese characters correctly 2`] = ` + 按钮 `; exports[`Button renders Chinese characters correctly 3`] = ` @@ -38,4 +38,6 @@ exports[`Button renders Chinese characters correctly 5`] = ` exports[`Button renders correctly 1`] = ``; -exports[`Button should support link button 1`] = `link button`; +exports[`Button should not render as link button when href is undefined 1`] = ``; + +exports[`Button should support link button 1`] = `link button`; diff --git a/components/button/__tests__/index.test.js b/components/button/__tests__/index.test.js index ca29d43950..5f0ec9bdd0 100644 --- a/components/button/__tests__/index.test.js +++ b/components/button/__tests__/index.test.js @@ -173,4 +173,15 @@ describe('Button', () => { }) expect(wrapper2.html()).toMatchSnapshot() }) + + it('should not render as link button when href is undefined', async () => { + const wrapper = mount({ + render () { + return ( + + ) + }, + }) + expect(wrapper.html()).toMatchSnapshot() + }) }) diff --git a/components/button/button.jsx b/components/button/button.jsx index b22228b400..73e1a926c0 100644 --- a/components/button/button.jsx +++ b/components/button/button.jsx @@ -3,13 +3,13 @@ import Icon from '../icon' const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/ const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar) import buttonTypes from './buttonTypes' +import { filterEmpty } from '../_util/props-util' const props = buttonTypes() export default { + inheritAttrs: false, name: 'AButton', __ANT_BUTTON: true, - props: { - ...props, - }, + props, data () { return { sizeMap: { @@ -48,13 +48,15 @@ export default { computed: { classes () { const { prefixCls, type, shape, size, hasTwoCNChar, - sLoading, ghost, block, sizeMap } = this + sLoading, ghost, block, sizeMap, icon, $slots } = this const sizeCls = sizeMap[size] || '' + const children = filterEmpty($slots.default) return { [`${prefixCls}`]: true, [`${prefixCls}-${type}`]: type, [`${prefixCls}-${shape}`]: shape, [`${prefixCls}-${sizeCls}`]: sizeCls, + [`${prefixCls}-icon-only`]: !children && children !== 0 && icon, [`${prefixCls}-loading`]: sLoading, [`${prefixCls}-background-ghost`]: ghost || type === 'ghost', [`${prefixCls}-two-chinese-chars`]: hasTwoCNChar, @@ -106,11 +108,8 @@ export default { disabled, handleClick, sLoading, $slots, $attrs, $listeners } = this const buttonProps = { - props: { - }, attrs: { ...$attrs, - type: htmlType, disabled, }, class: classes, @@ -121,9 +120,10 @@ 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 + const children = filterEmpty($slots.default) + const kids = children.map(child => this.insertSpace(child, this.isNeedInserted())) - if ('href' in $attrs) { + if ($attrs.href !== undefined) { return ( {iconNode}{kids} @@ -132,7 +132,7 @@ export default { } else { return ( - diff --git a/components/button/style/index.less b/components/button/style/index.less index c2a1cbf601..6f782647e0 100644 --- a/components/button/style/index.less +++ b/components/button/style/index.less @@ -1,8 +1,8 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; -@import "./mixin"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; +@import './mixin'; -@btn-prefix-cls: ~"@{ant-prefix}-btn"; +@btn-prefix-cls: ~'@{ant-prefix}-btn'; // for compatible @btn-ghost-color: @text-color; @@ -82,16 +82,24 @@ right: -1px; background: #fff; opacity: 0.35; - content: ""; + content: ''; border-radius: inherit; z-index: 1; - transition: opacity .2s; + transition: opacity 0.2s; pointer-events: none; display: none; } .@{iconfont-css-prefix} { - transition: margin-left .3s @ease-in-out; + transition: margin-left 0.3s @ease-in-out; + // Follow icon blur under windows. Change the render. + // https://github.com/ant-design/ant-design/issues/13924 + &.@{iconfont-css-prefix}-plus, + &.@{iconfont-css-prefix}-minus { + > svg { + shape-rendering: optimizeSpeed; + } + } } &&-loading:before { @@ -102,7 +110,7 @@ padding-left: 29px; pointer-events: none; position: relative; - .@{iconfont-css-prefix} { + .@{iconfont-css-prefix}:not(:last-child) { margin-left: -14px; } } @@ -150,12 +158,12 @@ } &-two-chinese-chars:first-letter { - letter-spacing: .34em; + letter-spacing: 0.34em; } &-two-chinese-chars > *:not(.@{iconfont-css-prefix}) { - letter-spacing: .34em; - margin-right: -.34em; + letter-spacing: 0.34em; + margin-right: -0.34em; } &-block { diff --git a/components/button/style/mixin.less b/components/button/style/mixin.less index 138ca49036..285d47cff8 100644 --- a/components/button/style/mixin.less +++ b/components/button/style/mixin.less @@ -24,17 +24,21 @@ .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); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); &:hover, &:focus { - .button-color(@color; ~`colorPalette("@{background}", 5)`; ~`colorPalette("@{background}", 5)`); + .button-color( + @color; ~`colorPalette('@{background}', 5) `; ~`colorPalette('@{background}', 5) ` + ); } &:active, &.active { - .button-color(@color; ~`colorPalette("@{background}", 7)`; ~`colorPalette("@{background}", 7)`); + .button-color( + @color; ~`colorPalette('@{background}', 7) `; ~`colorPalette('@{background}', 7) ` + ); } .button-disabled(); @@ -60,16 +64,20 @@ .button-color(@color; @background; @border); &:hover { - .button-color(@btn-primary-color; ~`colorPalette("@{color}", 5)`; ~`colorPalette("@{color}", 5)`); + .button-color( + @btn-primary-color; ~`colorPalette('@{color}', 5) `; ~`colorPalette('@{color}', 5) ` + ); } &:focus { - .button-color(~`colorPalette("@{color}", 5)`; #fff; ~`colorPalette("@{color}", 5)`); + .button-color(~`colorPalette('@{color}', 5) `; #fff; ~`colorPalette('@{color}', 5) `); } &:active, &.active { - .button-color(@btn-primary-color; ~`colorPalette("@{color}", 7)`; ~`colorPalette("@{color}", 7)`); + .button-color( + @btn-primary-color; ~`colorPalette('@{color}', 7) `; ~`colorPalette('@{color}', 7) ` + ); } .button-disabled(); @@ -81,12 +89,12 @@ &:hover, &:focus { - .button-color(~`colorPalette("@{color}", 5)`; transparent; ~`colorPalette("@{color}", 5)`); + .button-color(~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `); } &:active, &.active { - .button-color(~`colorPalette("@{color}", 7)`; transparent; ~`colorPalette("@{color}", 7)`); + .button-color(~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `); } .button-disabled(); @@ -101,7 +109,7 @@ > a:only-child { color: currentColor; &:after { - content: ""; + content: ''; position: absolute; top: 0; left: 0; @@ -161,9 +169,9 @@ white-space: nowrap; .button-size(@btn-height-base; @btn-padding-base; @font-size-base; @btn-border-radius-base); user-select: none; - transition: all .3s @ease-in-out; + transition: all 0.3s @ease-in-out; position: relative; - box-shadow: 0 2px 0 rgba(0, 0, 0, .015); + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); > .@{iconfont-css-prefix} { line-height: 1; diff --git a/components/calendar/__tests__/__snapshots__/demo.test.js.snap b/components/calendar/__tests__/__snapshots__/demo.test.js.snap index 00db10164f..af57788147 100644 --- a/components/calendar/__tests__/__snapshots__/demo.test.js.snap +++ b/components/calendar/__tests__/__snapshots__/demo.test.js.snap @@ -4,17 +4,17 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
-
+
2016
-
+
-
+
Nov
-
+
@@ -310,17 +310,17 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
-
+
2016
-
+
-
+
Nov
-
+
@@ -616,17 +616,17 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
-
+
2016
-
+
-
+
Nov
-
+
@@ -1029,17 +1029,17 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
-
+
2017
-
+
-
+
Jan
-
+
@@ -1333,17 +1333,17 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
-
+
2017
-
+
-
+
Jan
-
+
diff --git a/components/calendar/__tests__/__snapshots__/index.test.js.snap b/components/calendar/__tests__/__snapshots__/index.test.js.snap index 6f1ea3eb19..2a8cfe8f88 100644 --- a/components/calendar/__tests__/__snapshots__/index.test.js.snap +++ b/components/calendar/__tests__/__snapshots__/index.test.js.snap @@ -4,17 +4,17 @@ exports[`Calendar Calendar should support locale 1`] = `
-
+
2018年
-
+
-
+
Oct
-
+
diff --git a/components/calendar/locale/da_DK.js b/components/calendar/locale/da_DK.js new file mode 100644 index 0000000000..01f9b5333b --- /dev/null +++ b/components/calendar/locale/da_DK.js @@ -0,0 +1,2 @@ +import da_DK from '../../date-picker/locale/da_DK' +export default da_DK diff --git a/components/calendar/locale/he_IL.js b/components/calendar/locale/he_IL.js new file mode 100644 index 0000000000..b04226dccf --- /dev/null +++ b/components/calendar/locale/he_IL.js @@ -0,0 +1,2 @@ +import he_IL from '../../date-picker/locale/he_IL' +export default he_IL diff --git a/components/calendar/locale/hu_HU.js b/components/calendar/locale/hu_HU.js new file mode 100644 index 0000000000..12326461c0 --- /dev/null +++ b/components/calendar/locale/hu_HU.js @@ -0,0 +1,2 @@ +import hu_HU from '../../date-picker/locale/hu_HU' +export default hu_HU diff --git a/components/calendar/locale/id_ID.js b/components/calendar/locale/id_ID.js new file mode 100644 index 0000000000..39887f3439 --- /dev/null +++ b/components/calendar/locale/id_ID.js @@ -0,0 +1,2 @@ +import id_ID from '../../date-picker/locale/id_ID' +export default id_ID diff --git a/components/calendar/style/index.less b/components/calendar/style/index.less index 0db0f391bb..02581a5ac4 100644 --- a/components/calendar/style/index.less +++ b/components/calendar/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@full-calendar-prefix-cls: ~"@{ant-prefix}-fullcalendar"; +@full-calendar-prefix-cls: ~'@{ant-prefix}-fullcalendar'; .@{full-calendar-prefix-cls} { .reset-component; @@ -84,7 +84,7 @@ &-month, &-date { text-align: center; - transition: all .3s; + transition: all 0.3s; } &-value { @@ -97,7 +97,7 @@ padding: 0; background: transparent; line-height: 24px; - transition: all .3s; + transition: all 0.3s; &:hover { background: @item-hover-bg; @@ -180,7 +180,7 @@ height: 116px; padding: 4px 8px; border-top: 2px solid @border-color-split; - transition: background .3s; + transition: background 0.3s; &:hover { background: @item-hover-bg; diff --git a/components/card/__tests__/__snapshots__/demo.test.js.snap b/components/card/__tests__/__snapshots__/demo.test.js.snap index f7effd1686..f02dc83b56 100644 --- a/components/card/__tests__/__snapshots__/demo.test.js.snap +++ b/components/card/__tests__/__snapshots__/demo.test.js.snap @@ -268,15 +268,15 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = `
-
+
-
-
+
+
-
+
@@ -303,16 +303,16 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = `
-
+
-
-
+
+
-
+
diff --git a/components/card/style/index.less b/components/card/style/index.less index 9ecb1f2c30..effdb88e73 100644 --- a/components/card/style/index.less +++ b/components/card/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@card-prefix-cls: ~"@{ant-prefix}-card"; +@card-prefix-cls: ~'@{ant-prefix}-card'; @card-head-height: 48px; @card-hover-border: rgba(0, 0, 0, 0.09); @card-radius: @border-radius-sm; @@ -11,7 +11,7 @@ background: @component-background; border-radius: @card-radius; position: relative; - transition: all .3s; + transition: all 0.3s; &-hoverable { cursor: pointer; @@ -66,11 +66,10 @@ &-extra { float: right; - padding: @card-head-padding + 1.5px 0; + padding: @card-head-padding 0; font-size: @font-size-base; color: @text-color; font-weight: normal; - text-align: right; // https://stackoverflow.com/a/22429853/3040605 margin-left: auto; } @@ -88,11 +87,13 @@ &-grid { border-radius: 0; border: 0; - box-shadow: 1px 0 0 0 @border-color-split, 0 1px 0 0 @border-color-split, 1px 1px 0 0 @border-color-split, 1px 0 0 0 @border-color-split inset, 0 1px 0 0 @border-color-split inset; + box-shadow: 1px 0 0 0 @border-color-split, 0 1px 0 0 @border-color-split, + 1px 1px 0 0 @border-color-split, 1px 0 0 0 @border-color-split inset, + 0 1px 0 0 @border-color-split inset; width: 33.33%; float: left; padding: @card-padding-base; - transition: all .3s; + transition: all 0.3s; &:hover { position: relative; z-index: 1; @@ -143,7 +144,7 @@ &:hover { color: @primary-color; - transition: color .3s; + transition: color 0.3s; } & > .anticon { @@ -179,7 +180,7 @@ &-padding-transition &-head, &-padding-transition &-body { - transition: padding .3s; + transition: padding 0.3s; } &-type-inner &-head { @@ -230,6 +231,21 @@ } } + &-loading { + overflow: hidden; + position: relative; + + &:after { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: @card-padding-base; + background: @component-background; + content: ''; + } + } + &-loading &-body { user-select: none; } @@ -244,7 +260,12 @@ height: 14px; margin: 4px 0; border-radius: @card-radius; - background: linear-gradient(90deg, rgba(207, 216, 220, .2), rgba(207, 216, 220, .4), rgba(207, 216, 220, .2)); + background: linear-gradient( + 90deg, + rgba(207, 216, 220, 0.2), + rgba(207, 216, 220, 0.4), + rgba(207, 216, 220, 0.2) + ); animation: card-loading 1.4s ease infinite; background-size: 600% 600%; } @@ -253,9 +274,9 @@ @keyframes card-loading { 0%, 100% { - background-position: 0 50%; - } - 50% { - background-position: 100% 50%; - } + background-position: 0 50%; + } + 50% { + background-position: 100% 50%; + } } diff --git a/components/carousel/__tests__/index.test.js b/components/carousel/__tests__/index.test.js index 03e17e5fb9..d5a19c066d 100644 --- a/components/carousel/__tests__/index.test.js +++ b/components/carousel/__tests__/index.test.js @@ -77,7 +77,7 @@ describe('Carousel', () => { sync: true, } const wrapper = mount(Carousel, props) - const onWindowResized = wrapper.vm.onWindowResized + const { onWindowResized } = wrapper.vm const spy = jest.spyOn(wrapper.vm.onWindowResized, 'cancel') const spy2 = jest.spyOn(window, 'removeEventListener') wrapper.destroy() diff --git a/components/carousel/style/index.less b/components/carousel/style/index.less index 64d1267c71..19eff4e177 100644 --- a/components/carousel/style/index.less +++ b/components/carousel/style/index.less @@ -1,5 +1,5 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; .@{ant-prefix}-carousel { .reset-component; @@ -49,7 +49,7 @@ &:before, &:after { - content: ""; + content: ''; display: table; } @@ -65,7 +65,7 @@ float: left; height: 100%; min-height: 1px; - [dir="rtl"] & { + [dir='rtl'] & { float: right; } img { @@ -133,14 +133,14 @@ .slick-prev { left: -25px; &:before { - content: "←"; + content: '←'; } } .slick-next { right: -25px; &:before { - content: "→"; + content: '→'; } } @@ -174,7 +174,7 @@ outline: none; font-size: 0; color: transparent; - transition: all .5s; + transition: all 0.5s; padding: 0; &:hover, &:focus { diff --git a/components/cascader/__tests__/__snapshots__/demo.test.js.snap b/components/cascader/__tests__/__snapshots__/demo.test.js.snap index 6f6d5e0174..223ad17c3d 100644 --- a/components/cascader/__tests__/__snapshots__/demo.test.js.snap +++ b/components/cascader/__tests__/__snapshots__/demo.test.js.snap @@ -1,19 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders ./components/cascader/demo/basic.md correctly 1`] = ` - `; exports[`renders ./components/cascader/demo/change-on-select.md correctly 1`] = ` - `; exports[`renders ./components/cascader/demo/custom-render.md correctly 1`] = ` - + Zhejiang / Hangzhou / @@ -34,7 +34,7 @@ exports[`renders ./components/cascader/demo/custom-trigger.md correctly 1`] = ` `; exports[`renders ./components/cascader/demo/default-value.md correctly 1`] = ` -Zhejiang / Hangzhou / West LakeZhejiang / Hangzhou / West Lake `; exports[`renders ./components/cascader/demo/fields-name.md correctly 1`] = ` - `; exports[`renders ./components/cascader/demo/hover.md correctly 1`] = ` - `; exports[`renders ./components/cascader/demo/lazy.md correctly 1`] = ` - `; exports[`renders ./components/cascader/demo/search.md correctly 1`] = ` - `; exports[`renders ./components/cascader/demo/size.md correctly 1`] = ` -










`; exports[`renders ./components/cascader/demo/suffix.md correctly 1`] = ` -
ab
+
ab
`; diff --git a/components/cascader/__tests__/__snapshots__/index.test.js.snap b/components/cascader/__tests__/__snapshots__/index.test.js.snap index 291597ae73..8b4fc838c7 100644 --- a/components/cascader/__tests__/__snapshots__/index.test.js.snap +++ b/components/cascader/__tests__/__snapshots__/index.test.js.snap @@ -95,7 +95,7 @@ exports[`Cascader popup correctly with defaultValue 1`] = ` `; exports[`Cascader support controlled mode 1`] = ` -Zhejiang / Hangzhou / West LakeZhejiang / Hangzhou / West Lake ) + const getPopupContainer = props.getPopupContainer || getContextPopupContainer const cascaderProps = { props: { ...props, + getPopupContainer, options: options, value: value, popupVisible: sPopupVisible, diff --git a/components/cascader/index.zh-CN.md b/components/cascader/index.zh-CN.md index 1a0d58d171..19e4a9970a 100644 --- a/components/cascader/index.zh-CN.md +++ b/components/cascader/index.zh-CN.md @@ -34,6 +34,7 @@ | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | filter | 接收 `inputValue` `path` 两个参数,当 `path` 符合筛选条件时,应返回 true,反之则返回 false。 | `function(inputValue, path): boolean` | | +| limit | 搜索结果展示数量 | number \| false | 50 | | matchInputWidth | 搜索结果列表是否与输入框同宽 | boolean | | | render | 用于渲染 filter 后的选项,可使用slot="showSearchRender" 和 slot-scope="{inputValue, path}" | `function({inputValue, path}): vNode` | | | sort | 用于排序 filter 后的选项 | `function(a, b, inputValue)` | | diff --git a/components/cascader/style/index.less b/components/cascader/style/index.less index 5de52826eb..a688905cf5 100644 --- a/components/cascader/style/index.less +++ b/components/cascader/style/index.less @@ -1,8 +1,8 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; -@import "../../input/style/mixin"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; +@import '../../input/style/mixin'; -@cascader-prefix-cls: ~"@{ant-prefix}-cascader"; +@cascader-prefix-cls: ~'@{ant-prefix}-cascader'; .@{cascader-prefix-cls} { .reset-component; @@ -28,7 +28,7 @@ background-color: @component-background; border-radius: @border-radius-base; outline: 0; - transition: color .3s; + transition: color 0.3s; &-with-value &-label { color: transparent; @@ -101,7 +101,7 @@ margin-top: -6px; line-height: 12px; color: @disabled-color; - transition: transform .2s; + transition: transform 0.2s; &&-expand { transform: rotate(180deg); } diff --git a/components/checkbox/Group.jsx b/components/checkbox/Group.jsx index 4e2e8c989c..fe993ef012 100644 --- a/components/checkbox/Group.jsx +++ b/components/checkbox/Group.jsx @@ -44,7 +44,7 @@ export default { }, methods: { getOptions () { - const { options } = this.$props + const { options, $scopedSlots } = this return options.map(option => { if (typeof option === 'string') { return { @@ -52,7 +52,11 @@ export default { value: option, } } - return option + let label = option.label + if (label === undefined && $scopedSlots.label) { + label = $scopedSlots.label(option) + } + return { ...option, label } }) }, toggleOption (option) { diff --git a/components/checkbox/__tests__/__snapshots__/demo.test.js.snap b/components/checkbox/__tests__/__snapshots__/demo.test.js.snap index 1a8b855420..72d6526c2f 100644 --- a/components/checkbox/__tests__/__snapshots__/demo.test.js.snap +++ b/components/checkbox/__tests__/__snapshots__/demo.test.js.snap @@ -27,7 +27,7 @@ exports[`renders ./components/checkbox/demo/group.md correctly 1`] = `



-
+
`; diff --git a/components/checkbox/demo/group.md b/components/checkbox/demo/group.md index eb6c696af7..19b3b54985 100644 --- a/components/checkbox/demo/group.md +++ b/components/checkbox/demo/group.md @@ -17,7 +17,9 @@ Generate a group of checkboxes from an array

- + + {{value}} +
+``` diff --git a/components/comment/demo/editor.md b/components/comment/demo/editor.md new file mode 100644 index 0000000000..d2855251dd --- /dev/null +++ b/components/comment/demo/editor.md @@ -0,0 +1,93 @@ + +#### 回复框 +评论编辑器组件提供了相同样式的封装以支持自定义评论编辑器。 + + + +#### Reply Editor +Comment can be used as editor, user can customize the editor component. + + +```html + + +``` diff --git a/components/comment/demo/index.vue b/components/comment/demo/index.vue new file mode 100644 index 0000000000..4dde889493 --- /dev/null +++ b/components/comment/demo/index.vue @@ -0,0 +1,52 @@ + diff --git a/components/comment/demo/list.md b/components/comment/demo/list.md new file mode 100644 index 0000000000..61f738f747 --- /dev/null +++ b/components/comment/demo/list.md @@ -0,0 +1,61 @@ + +#### 配合 List 组件 +配合 List 组件展现评论列表。 + + + +#### Usage with list +Displaying a series of comments using the `antd` List Component. + + +```html + + +``` diff --git a/components/comment/demo/nested.md b/components/comment/demo/nested.md new file mode 100644 index 0000000000..d8544d8b78 --- /dev/null +++ b/components/comment/demo/nested.md @@ -0,0 +1,54 @@ + +#### 嵌套评论 +评论可以嵌套。 + + + +#### Nested comments +Comments can be nested. + + +```html + +``` diff --git a/components/comment/index.en-US.md b/components/comment/index.en-US.md new file mode 100644 index 0000000000..ecde03e86f --- /dev/null +++ b/components/comment/index.en-US.md @@ -0,0 +1,9 @@ +## API + +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| actions | List of action items rendered below the comment content | Array \| slot | - | +| author | The element to display as the comment author | string\|slot | - | +| avatar | The element to display as the comment avatar - generally an antd `Avatar` or src | string\|slot | - | +| content | The main content of the comment | string\|slot | - | +| datetime | A datetime element containing the time to be displayed | string\|slot | - | diff --git a/components/comment/index.jsx b/components/comment/index.jsx new file mode 100644 index 0000000000..bdcb446ac0 --- /dev/null +++ b/components/comment/index.jsx @@ -0,0 +1,95 @@ +import PropsTypes from '../_util/vue-types' +import { initDefaultProps, getComponentFromProp } from '../_util/props-util' + +export const CommentProps = { + actions: PropsTypes.array, + /** The element to display as the comment author. */ + author: PropsTypes.any, + /** The element to display as the comment avatar - generally an antd Avatar */ + avatar: PropsTypes.any, + /** The main content of the comment */ + content: PropsTypes.any, + /** Comment prefix defaults to '.ant-comment' */ + prefixCls: PropsTypes.string, + /** A datetime element containing the time to be displayed */ + datetime: PropsTypes.any, +} + +const Comment = { + name: 'AComment', + props: initDefaultProps(CommentProps, { + prefixCls: 'ant-comment', + }), + methods: { + getAction (actions) { + if (!actions || !actions.length) { + return null + } + const actionList = actions.map((action, index) =>
  • {action}
  • ) + return actionList + }, + renderNested (children) { + const { prefixCls } = this.$props + + return
    {children}
    + }, + }, + + render () { + const { + prefixCls, + } = this.$props + + const actions = getComponentFromProp(this, 'actions') + const author = getComponentFromProp(this, 'author') + const avatar = getComponentFromProp(this, 'avatar') + const content = getComponentFromProp(this, 'content') + const datetime = getComponentFromProp(this, 'datetime') + + const avatarDom = ( +
    + {typeof avatar === 'string' ? : avatar} +
    + ) + + const actionDom = + actions && actions.length ? ( +
      {this.getAction(actions)}
    + ) : null + + const authorContent = ( + + ) + + const contentDom = ( +
    + {authorContent} +
    {content}
    + {actionDom} +
    + ) + + const comment = ( +
    + {avatarDom} + {contentDom} +
    + ) + const children = this.$slots.default + return ( +
    + {comment} + {children ? this.renderNested(children) : null} +
    + ) + }, +} + +/* istanbul ignore next */ +Comment.install = function (Vue) { + Vue.component(Comment.name, Comment) +} +export default Comment diff --git a/components/comment/index.zh-CN.md b/components/comment/index.zh-CN.md new file mode 100644 index 0000000000..b7455b5b07 --- /dev/null +++ b/components/comment/index.zh-CN.md @@ -0,0 +1,9 @@ +## API + +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| actions | 在评论内容下面呈现的操作项列表 | Array\|slot | - | +| author | 要显示为注释作者的元素 | string\|slot | - | +| avatar | 要显示为评论头像的元素 - 通常是 antd `Avatar` 或者src | string\|slot | - | +| content | 评论的主要内容 | string\|slot | - | +| datetime | 展示时间描述 | string\|slot | - | diff --git a/components/comment/style/index.js b/components/comment/style/index.js new file mode 100644 index 0000000000..3a3ab0de59 --- /dev/null +++ b/components/comment/style/index.js @@ -0,0 +1,2 @@ +import '../../style/index.less'; +import './index.less'; diff --git a/components/comment/style/index.less b/components/comment/style/index.less new file mode 100644 index 0000000000..891ea42098 --- /dev/null +++ b/components/comment/style/index.less @@ -0,0 +1,93 @@ +@import '../../style/themes/default'; +@import '../../style/mixins/index'; + +@comment-prefix-cls: ~'@{ant-prefix}-comment'; + +.@{comment-prefix-cls} { + position: relative; + + &-inner { + padding: @comment-padding-base; + display: flex; + } + + &-avatar { + flex-shrink: 0; + position: relative; + margin-right: 12px; + cursor: pointer; + img { + width: 32px; + height: 32px; + border-radius: 50%; + } + } + + &-content { + position: relative; + font-size: 14px; + flex: 1 1 auto; + min-width: 1px; + word-wrap: break-word; + + &-author { + margin-bottom: 4px; + font-size: 14px; + display: flex; + justify-content: flex-start; + & > a, + & > span { + height: 18px; + font-size: 12px; + line-height: 18px; + padding-right: 8px; + } + + &-name { + transition: color 0.3s; + font-size: 14px; + color: @comment-author-name-color; + > * { + color: @comment-author-name-color; + &:hover { + color: @comment-author-name-color; + } + } + } + + &-time { + cursor: auto; + color: @comment-author-time-color; + white-space: nowrap; + } + } + + &-detail p { + white-space: pre-wrap; + } + } + + &-actions { + margin-top: 12px; + padding-left: 0; + > li { + display: inline-block; + color: @comment-action-color; + > span { + padding-right: 10px; + transition: color 0.3s; + font-size: 12px; + color: @comment-action-color; + cursor: pointer; + user-select: none; + &:hover { + color: @comment-action-hover-color; + } + } + } + } + + &-nested { + margin-left: @comment-nest-indent; + } +} diff --git a/components/config-provider/demo/index.vue b/components/config-provider/demo/index.vue new file mode 100644 index 0000000000..08b0655ce5 --- /dev/null +++ b/components/config-provider/demo/index.vue @@ -0,0 +1,32 @@ + diff --git a/components/config-provider/index.en-US.md b/components/config-provider/index.en-US.md new file mode 100644 index 0000000000..52629e520b --- /dev/null +++ b/components/config-provider/index.en-US.md @@ -0,0 +1,16 @@ + +## Usage + +This component provides a configuration to all Vue components underneath itself via the [provide / inject](https://vuejs.org/v2/api/#provide-inject), In the render tree all components will have access to the provided config. + +````html + + + +```` + +## API + +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| getPopupContainer | to set the container of the popup element. The default is to create a `div` element in `body`. | Function(triggerNode) | `() => document.body` | diff --git a/components/config-provider/index.jsx b/components/config-provider/index.jsx new file mode 100644 index 0000000000..289f47327b --- /dev/null +++ b/components/config-provider/index.jsx @@ -0,0 +1,25 @@ + +import PropTypes from '../_util/vue-types' + +const ConfigProvider = { + name: 'AConfigProvider', + props: { + getPopupContainer: PropTypes.func, + }, + provide () { + return { + configProvider: this.$props, + } + }, + render () { + return this.$slots.default ? this.$slots.default[0] : null + }, +} + +/* istanbul ignore next */ +ConfigProvider.install = function (Vue) { + Vue.component(ConfigProvider.name, ConfigProvider) +} + +export default ConfigProvider + diff --git a/components/config-provider/index.zh-CN.md b/components/config-provider/index.zh-CN.md new file mode 100644 index 0000000000..5beed7964d --- /dev/null +++ b/components/config-provider/index.zh-CN.md @@ -0,0 +1,15 @@ +## 使用 + +ConfigProvider 使用 Vue 的 [provide / inject](https://vuejs.org/v2/api/#provide-inject) 特性,只需在应用外围包裹一次即可全局生效。 + +````html + + + +```` + +## API + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | Function(triggerNode) | () => document.body | diff --git a/components/config-provider/style/index.js b/components/config-provider/style/index.js new file mode 100644 index 0000000000..d74e52ee9f --- /dev/null +++ b/components/config-provider/style/index.js @@ -0,0 +1 @@ +import './index.less'; diff --git a/components/config-provider/style/index.less b/components/config-provider/style/index.less new file mode 100644 index 0000000000..df1dee5e0a --- /dev/null +++ b/components/config-provider/style/index.less @@ -0,0 +1,2 @@ +// placeholder +@import '../../style/themes/default'; diff --git a/components/date-picker/RangePicker.jsx b/components/date-picker/RangePicker.jsx index e62240197c..20af18d8c8 100644 --- a/components/date-picker/RangePicker.jsx +++ b/components/date-picker/RangePicker.jsx @@ -50,11 +50,12 @@ function fixLocale (value, localeCode) { if (!value || value.length === 0) { return } - if (value[0]) { - value[0].locale(localeCode) + const [start, end] = value + if (start) { + start.locale(localeCode) } - if (value[1]) { - value[1].locale(localeCode) + if (end) { + end.locale(localeCode) } } @@ -73,9 +74,10 @@ export default { }, data () { const value = this.value || this.defaultValue || [] + const [start, end] = value if ( - value[0] && !interopDefault(moment).isMoment(value[0]) || - value[1] && !interopDefault(moment).isMoment(value[1]) + start && !interopDefault(moment).isMoment(start) || + end && !interopDefault(moment).isMoment(end) ) { throw new Error( 'The value/defaultValue of RangePicker must be a moment object array after `antd@2.0`, ' + @@ -127,11 +129,11 @@ export default { sShowDate: getShowDateFromValue(value) || sShowDate, })) } + const [start, end] = value this.$emit('change', value, [ - formatValue(value[0], this.format), - formatValue(value[1], this.format), + formatValue(start, this.format), + formatValue(end, this.format), ]) - this.focus() }, handleOpenChange (open) { @@ -143,6 +145,10 @@ export default { this.clearHoverValue() } this.$emit('openChange', open) + + if (!open) { + this.focus() + } }, handleShowDateChange (showDate) { @@ -160,7 +166,8 @@ export default { }, handleCalendarInputSelect (value) { - if (!value[0]) { + const [start] = value + if (!start) { return } this.setState(({ sShowDate }) => ({ @@ -317,8 +324,8 @@ export default { if (props.showTime) { pickerStyle.width = '350px' } - - const clearIcon = (!props.disabled && props.allowClear && value && (value[0] || value[1])) ? ( + const [startValue, endValue] = value + const clearIcon = (!props.disabled && props.allowClear && value && (startValue || endValue)) ? ( { - const start = inputValue[0] - const end = inputValue[1] + const [start, end] = inputValue return ( ) - const clearIcon = (!disabled && allowClear && this.sValue) ? ( + const clearIcon = (!disabled && allowClear && $data._value) ? ( { return ( - +
    diff --git a/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap index e77c56ad67..387e423309 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 6c1e5f529c..ab062d2172 100644 --- a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap +++ b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap @@ -3,13 +3,13 @@ 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/disabled.md correctly 1`] = ` @@ -58,7 +58,7 @@ exports[`renders ./components/date-picker/demo/size.md correctly 1`] = `




    ~
    +
    `; @@ -67,7 +67,7 @@ exports[`renders ./components/date-picker/demo/start-end.md correctly 1`] = `


    ~

    ab

    ab

    ~ ab
    ab
    +

    ab

    ab

    ~ ab
    ab
    `; exports[`renders ./components/date-picker/demo/time.md correctly 1`] = ` diff --git a/components/date-picker/__tests__/showTime.test.js b/components/date-picker/__tests__/showTime.test.js index 1c72997f68..6e364d972f 100644 --- a/components/date-picker/__tests__/showTime.test.js +++ b/components/date-picker/__tests__/showTime.test.js @@ -1,5 +1,6 @@ import { mount } from '@vue/test-utils' import { asyncExpect } from '@/tests/utils' +import moment from 'moment' import DatePicker from '../' const { RangePicker } = DatePicker @@ -34,7 +35,14 @@ describe('DatePicker with showTime', () => { const onChangeFn = jest.fn() const wrapper = mount({ render () { - return + return }, }, { sync: false }) diff --git a/components/date-picker/createPicker.js b/components/date-picker/createPicker.js index d74f49fd22..8a3ed7efc1 100644 --- a/components/date-picker/createPicker.js +++ b/components/date-picker/createPicker.js @@ -92,7 +92,6 @@ export default function createPicker (TheCalendar, props) { }) } this.$emit('change', value, (value && value.format(this.format)) || '') - this.focus() }, handleCalendarChange (value) { @@ -104,6 +103,9 @@ export default function createPicker (TheCalendar, props) { this.setState({ _open: open }) } this.$emit('openChange', open) + if (!open) { + this.focus() + } }, focus () { this.$refs.input.focus() diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md index 03c19035ad..290c69eb92 100644 --- a/components/date-picker/index.en-US.md +++ b/components/date-picker/index.en-US.md @@ -80,7 +80,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke | -------- | ----------- | ---- | ------- | | 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" | +| format | to set the date format. When an array is provided, all values are used for parsing and first value for display. refer to [moment.js](http://momentjs.com/) | string \| 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" | - | | value(v-model) | to set date | [moment](http://momentjs.com/) | - | @@ -110,18 +110,18 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke | -------- | ----------- | ---- | ------- | | 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(dates: [moment, moment], partial: `'start'|'end'`) | - | +| 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/)\[] } | - | | 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()] | +| 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()] | | value(v-model) | to set date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - | ### 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]) | +| 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() | +| ok | callback when click ok button | function(dates: [moment](http://momentjs.com/)\[]) | diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md index 0df00d03c4..a1cd987870 100644 --- a/components/date-picker/index.zh-CN.md +++ b/components/date-picker/index.zh-CN.md @@ -60,7 +60,7 @@ moment.locale('zh-cn'); | defaultValue | 默认日期 | [moment](http://momentjs.com/) | 无 | | defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 | | disabledTime | 不可选择的时间 | function(date) | 无 | -| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM-DD" | +| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [moment.js](http://momentjs.com/) | string \| string[] | "YYYY-MM-DD" | | renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - | | showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/ant-design-vue/components/time-picker-cn/#API) | | showTime.defaultValue | 设置用户选择日期时默认的时分秒 | [moment](http://momentjs.com/) | moment() | @@ -112,19 +112,19 @@ moment.locale('zh-cn'); | --- | --- | --- | --- | | defaultValue | 默认日期 | [moment](http://momentjs.com/)\[] | 无 | | defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/)\[] | 无 | -| disabledTime | 不可选择的时间 | function(dates: [moment, moment], partial: `'start'|'end'`) | 无 | +| 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/)\[] } | 无 | | renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - | | showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/ant-design-vue/components/time-picker-cn/#API) | -| showTime.defaultValue | 设置用户选择日期时默认的时分秒 | [moment](http://momentjs.com/)\[] | [moment(), moment()] | +| showTime.defaultValue | 设置用户选择日期时默认的时分秒 | [moment](http://momentjs.com/)\[] | \[moment(), moment()] | | value(v-model) | 日期 | [moment](http://momentjs.com/)\[] | 无 | ### RangePicker事件 | 事件名称 | 说明 | 回调参数 | | --- | --- | --- | -| calendarChange | 待选日期发生变化的回调 | function(dates: [moment, moment], dateStrings: [string, string]) | -| change | 日期范围发生变化的回调 | function(dates: [moment, moment], dateStrings: [string, string]) | 无 | -| ok | 点击确定按钮的回调 | function() | +| calendarChange | 待选日期发生变化的回调 | function(dates: \[moment, moment\], dateStrings: \[string, string\]) | +| change | 日期范围发生变化的回调 | function(dates: \[moment, moment\], dateStrings: \[string, string\]) | 无 | +| ok | 点击确定按钮的回调 | function(dates: [moment](http://momentjs.com/)\[]) | diff --git a/components/date-picker/interface.js b/components/date-picker/interface.js index 42b1a37c2a..b759a6b638 100644 --- a/components/date-picker/interface.js +++ b/components/date-picker/interface.js @@ -13,7 +13,7 @@ export const PickerProps = () => ({ transitionName: PropTypes.string, prefixCls: PropTypes.string, inputPrefixCls: PropTypes.string, - format: PropTypes.string, + format: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), disabled: PropTypes.bool, allowClear: PropTypes.bool, suffixIcon: PropTypes.any, diff --git a/components/date-picker/locale/da_DK.js b/components/date-picker/locale/da_DK.js new file mode 100644 index 0000000000..ce506b97f9 --- /dev/null +++ b/components/date-picker/locale/da_DK.js @@ -0,0 +1,19 @@ +import CalendarLocale from '../../vc-calendar/src/locale/da_DK' +import TimePickerLocale from '../../time-picker/locale/da_DK' + +// Merge into a locale object +const locale = { + lang: { + placeholder: 'Vælg dato', + rangePlaceholder: ['Startdato', 'Slutdato'], + ...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/he_IL.js b/components/date-picker/locale/he_IL.js new file mode 100644 index 0000000000..d0df808d81 --- /dev/null +++ b/components/date-picker/locale/he_IL.js @@ -0,0 +1,19 @@ +import CalendarLocale from '../../vc-calendar/src/locale/he_IL' +import TimePickerLocale from '../../time-picker/locale/he_IL' + +// 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/hu_HU.js b/components/date-picker/locale/hu_HU.js new file mode 100644 index 0000000000..189819675a --- /dev/null +++ b/components/date-picker/locale/hu_HU.js @@ -0,0 +1,19 @@ +import CalendarLocale from '../../vc-calendar/src/locale/hu_HU' +import TimePickerLocale from '../../time-picker/locale/hu_HU' + +// Merge into a locale object +const locale = { + lang: { + placeholder: 'Válasszon dátumot', + rangePlaceholder: ['Kezdő dátum', 'Befejezés dátuma'], + ...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/id_ID.js b/components/date-picker/locale/id_ID.js new file mode 100644 index 0000000000..46c76de7c1 --- /dev/null +++ b/components/date-picker/locale/id_ID.js @@ -0,0 +1,19 @@ +import CalendarLocale from '../../vc-calendar/src/locale/id_ID' +import TimePickerLocale from '../../time-picker/locale/id_ID' + +// Merge into a locale object +const locale = { + lang: { + placeholder: 'Pilih tanggal', + rangePlaceholder: ['Mulai tanggal', 'Tanggal akhir'], + ...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/style/Calendar.less b/components/date-picker/style/Calendar.less index 93fed470de..7fc09eb7d4 100644 --- a/components/date-picker/style/Calendar.less +++ b/components/date-picker/style/Calendar.less @@ -38,7 +38,7 @@ position: absolute; top: 0; color: @text-color-secondary; - font-family: Arial, "Hiragino Sans GB", "Microsoft Yahei", "Microsoft Sans Serif", sans-serif; + font-family: Arial, 'Hiragino Sans GB', 'Microsoft Yahei', 'Microsoft Sans Serif', sans-serif; padding: 0 5px; font-size: 16px; display: inline-block; @@ -214,7 +214,9 @@ background: tint(@primary-color, 80%); } - &-selected-date, &-selected-start-date, &-selected-end-date { + &-selected-date, + &-selected-start-date, + &-selected-end-date { .@{calendar-prefix-cls}-date { background: @primary-color; color: #fff; @@ -240,10 +242,10 @@ } &-disabled-cell&-today &-date { position: relative; - margin-right: 5px; + padding-right: 5px; padding-left: 5px; &:before { - content: " "; + content: ' '; position: absolute; top: -1px; left: 5px; diff --git a/components/date-picker/style/DecadePanel.less b/components/date-picker/style/DecadePanel.less index fc563ebbfd..386eb3aab7 100644 --- a/components/date-picker/style/DecadePanel.less +++ b/components/date-picker/style/DecadePanel.less @@ -15,11 +15,11 @@ } .@{calendar-prefix-cls}-decade-panel-header { - .calendarPanelHeader(~"@{calendar-prefix-cls}-decade-panel"); + .calendarPanelHeader(~'@{calendar-prefix-cls}-decade-panel'); } .@{calendar-prefix-cls}-decade-panel-body { - height: ~"calc(100% - 40px)"; + height: ~'calc(100% - 40px)'; } .@{calendar-prefix-cls}-decade-panel-table { diff --git a/components/date-picker/style/MonthPanel.less b/components/date-picker/style/MonthPanel.less index fbeceec8c3..e2d7a0b91f 100644 --- a/components/date-picker/style/MonthPanel.less +++ b/components/date-picker/style/MonthPanel.less @@ -9,7 +9,8 @@ background: @component-background; outline: none; - > div { // TODO: this is a useless wrapper, and we need to remove it in rc-calendar + > div { + // TODO: this is a useless wrapper, and we need to remove it in rc-calendar height: 100%; } } @@ -19,11 +20,11 @@ } .@{calendar-prefix-cls}-month-panel-header { - .calendarPanelHeader(~"@{calendar-prefix-cls}-month-panel"); + .calendarPanelHeader(~'@{calendar-prefix-cls}-month-panel'); } .@{calendar-prefix-cls}-month-panel-body { - height: ~"calc(100% - 40px)"; + height: ~'calc(100% - 40px)'; } .@{calendar-prefix-cls}-month-panel-table { diff --git a/components/date-picker/style/Picker.less b/components/date-picker/style/Picker.less index b9b085a88a..cddc67f9fa 100644 --- a/components/date-picker/style/Picker.less +++ b/components/date-picker/style/Picker.less @@ -1,4 +1,4 @@ -@import "../../button/style/mixin"; +@import '../../button/style/mixin'; .@{calendar-prefix-cls}-picker-container { .reset-component; @@ -65,7 +65,7 @@ margin-top: -7px; line-height: 14px; font-size: @font-size-sm; - transition: all .3s; + transition: all 0.3s; user-select: none; z-index: 1; } @@ -89,7 +89,7 @@ } &-icon { - font-family: "anticon"; + font-family: 'anticon'; font-size: @font-size-base; color: @disabled-color; display: inline-block; diff --git a/components/date-picker/style/RangePicker.less b/components/date-picker/style/RangePicker.less index 62cfe035db..94b0ef66c7 100644 --- a/components/date-picker/style/RangePicker.less +++ b/components/date-picker/style/RangePicker.less @@ -28,7 +28,7 @@ .@{calendar-prefix-cls}-date-panel { &::after { - content: "."; + content: '.'; display: block; height: 0; clear: both; @@ -134,7 +134,7 @@ z-index: 1; } &:before { - content: ""; + content: ''; display: block; background: @item-active-bg; border-radius: 0; diff --git a/components/date-picker/style/TimePicker.less b/components/date-picker/style/TimePicker.less index 6bda075469..25e080cdcd 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/style/WeekPicker.less b/components/date-picker/style/WeekPicker.less index c2f6748080..83eecea40a 100644 --- a/components/date-picker/style/WeekPicker.less +++ b/components/date-picker/style/WeekPicker.less @@ -3,7 +3,7 @@ opacity: 0.5; } .@{calendar-prefix-cls}-body tr { - transition: all .3s; + transition: all 0.3s; cursor: pointer; &:hover { background: @primary-1; diff --git a/components/date-picker/style/YearPanel.less b/components/date-picker/style/YearPanel.less index cd7a328bc8..8c7dd764a7 100644 --- a/components/date-picker/style/YearPanel.less +++ b/components/date-picker/style/YearPanel.less @@ -9,7 +9,8 @@ background: @component-background; outline: none; - > div { // TODO: this is a useless wrapper, and we need to remove it in rc-calendar + > div { + // TODO: this is a useless wrapper, and we need to remove it in rc-calendar height: 100%; } } @@ -19,11 +20,11 @@ } .@{calendar-prefix-cls}-year-panel-header { - .calendarPanelHeader(~"@{calendar-prefix-cls}-year-panel"); + .calendarPanelHeader(~'@{calendar-prefix-cls}-year-panel'); } .@{calendar-prefix-cls}-year-panel-body { - height: ~"calc(100% - 40px)"; + height: ~'calc(100% - 40px)'; } .@{calendar-prefix-cls}-year-panel-table { diff --git a/components/date-picker/style/index.less b/components/date-picker/style/index.less index 466b7e889f..d8e6026dc7 100644 --- a/components/date-picker/style/index.less +++ b/components/date-picker/style/index.less @@ -1,17 +1,17 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; -@import "../../input/style/mixin"; -@import "../../button/style/mixin"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; +@import '../../input/style/mixin'; +@import '../../button/style/mixin'; -@calendar-prefix-cls: ~"@{ant-prefix}-calendar"; -@calendar-timepicker-prefix-cls: ~"@{ant-prefix}-calendar-time-picker"; +@calendar-prefix-cls: ~'@{ant-prefix}-calendar'; +@calendar-timepicker-prefix-cls: ~'@{ant-prefix}-calendar-time-picker'; -@import "Picker"; -@import "Calendar"; -@import "RangePicker"; -@import "TimePicker"; -@import "MonthPanel"; -@import "YearPanel"; -@import "DecadePanel"; -@import "MonthPicker"; -@import "WeekPicker"; +@import 'Picker'; +@import 'Calendar'; +@import 'RangePicker'; +@import 'TimePicker'; +@import 'MonthPanel'; +@import 'YearPanel'; +@import 'DecadePanel'; +@import 'MonthPicker'; +@import 'WeekPicker'; diff --git a/components/divider/style/index.less b/components/divider/style/index.less index c7e6411899..c6ff97b747 100644 --- a/components/divider/style/index.less +++ b/components/divider/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@divider-prefix-cls: ~"@{ant-prefix}-divider"; +@divider-prefix-cls: ~'@{ant-prefix}-divider'; .@{divider-prefix-cls} { .reset-component; @@ -39,7 +39,7 @@ margin: 16px 0; &:before, &:after { - content: ""; + content: ''; display: table-cell; position: relative; top: 50%; diff --git a/components/drawer/__tests__/MultiDrawer.test.js b/components/drawer/__tests__/MultiDrawer.test.js index 8e84fb23b6..d283954dc4 100644 --- a/components/drawer/__tests__/MultiDrawer.test.js +++ b/components/drawer/__tests__/MultiDrawer.test.js @@ -133,7 +133,7 @@ describe('Drawer', () => { wrapper.find('#open_two_drawer').trigger('click') }, 0) await asyncExpect(() => { - const translateX = wrapper.find('.ant-drawer.test_drawer').element.parentElement.style.transform + const translateX = wrapper.find('.ant-drawer.test_drawer').element.style.transform expect(translateX).toEqual('translateX(-180px)') expect(wrapper.find('#two_drawer_text').exists()).toBe(true) }, 1000) @@ -154,7 +154,7 @@ describe('Drawer', () => { wrapper.find('#open_two_drawer').trigger('click') }, 0) await asyncExpect(() => { - const translateX = wrapper.find('.ant-drawer.test_drawer').element.parentElement.style.transform + const translateX = wrapper.find('.ant-drawer.test_drawer').element.style.transform expect(translateX).toEqual('translateX(180px)') expect(wrapper.find('#two_drawer_text').exists()).toBe(true) }, 1000) @@ -174,7 +174,7 @@ describe('Drawer', () => { wrapper.find('#open_two_drawer').trigger('click') }, 0) await asyncExpect(() => { - const translateY = wrapper.find('.ant-drawer.test_drawer').element.parentElement.style.transform + const translateY = wrapper.find('.ant-drawer.test_drawer').element.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 688d5207a8..4bbd01d5d1 100644 --- a/components/drawer/__tests__/__snapshots__/Drawer.test.js.snap +++ b/components/drawer/__tests__/__snapshots__/Drawer.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Drawer class is test_drawer 1`] = ` -
    +
    @@ -16,7 +16,7 @@ exports[`Drawer class is test_drawer 1`] = ` `; exports[`Drawer closable is false 1`] = ` -
    +
    @@ -31,7 +31,7 @@ exports[`Drawer closable is false 1`] = ` `; exports[`Drawer destroyOnClose is true 1`] = ` -
    +
    @@ -46,7 +46,7 @@ exports[`Drawer destroyOnClose is true 1`] = ` `; exports[`Drawer have a title 1`] = ` -
    +
    @@ -64,7 +64,7 @@ exports[`Drawer have a title 1`] = ` `; exports[`Drawer render correctly 1`] = ` -
    +
    @@ -79,7 +79,7 @@ exports[`Drawer render correctly 1`] = ` `; exports[`Drawer render top drawer 1`] = ` -
    +
    diff --git a/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap b/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap index efd6a7c4ee..7b7a6091f8 100644 --- a/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap +++ b/components/drawer/__tests__/__snapshots__/DrawerEvent.test.js.snap @@ -2,7 +2,7 @@ exports[`Drawer render correctly 1`] = `
    -
    +
    diff --git a/components/drawer/__tests__/__snapshots__/demo.test.js.snap b/components/drawer/__tests__/__snapshots__/demo.test.js.snap index 5723e20955..d470284fdb 100644 --- a/components/drawer/__tests__/__snapshots__/demo.test.js.snap +++ b/components/drawer/__tests__/__snapshots__/demo.test.js.snap @@ -6,6 +6,14 @@ exports[`renders ./components/drawer/demo/basic-right.md correctly 1`] = `
    `; +exports[`renders ./components/drawer/demo/form-in-drawer.md correctly 1`] = ` +
    + +
    +`; + exports[`renders ./components/drawer/demo/multi-level-drawer.md correctly 1`] = `
    diff --git a/components/drawer/__tests__/demo.test.js b/components/drawer/__tests__/demo.test.js index 975152a9a8..6959107307 100644 --- a/components/drawer/__tests__/demo.test.js +++ b/components/drawer/__tests__/demo.test.js @@ -1,3 +1,3 @@ import demoTest from '../../../tests/shared/demoTest' -demoTest('drawer', { skip: ['from-drawer.md'] }) +demoTest('drawer') diff --git a/components/drawer/demo/form-in-drawer.md b/components/drawer/demo/form-in-drawer.md new file mode 100644 index 0000000000..c6b392195e --- /dev/null +++ b/components/drawer/demo/form-in-drawer.md @@ -0,0 +1,159 @@ + +#### 抽屉表单 +在抽屉中使用表单。 + + + +#### Submit form in drawer +Use form in drawer with submit button. + + +```html + + +``` diff --git a/components/drawer/demo/from-drawer.md b/components/drawer/demo/from-drawer.md deleted file mode 100644 index ffcf698c70..0000000000 --- a/components/drawer/demo/from-drawer.md +++ /dev/null @@ -1,131 +0,0 @@ - -#### 对象编辑 -用于承载编辑相关操作,需要点击关闭按钮关闭。 - - - -#### Edit item in drawer -A drawer containing an editable form which needs to be collapsed by clicking the close button. - - -```html - - -``` diff --git a/components/drawer/demo/index.vue b/components/drawer/demo/index.vue index 15c24c5eac..c1db9a4a67 100644 --- a/components/drawer/demo/index.vue +++ b/components/drawer/demo/index.vue @@ -3,7 +3,7 @@ import BasicRight from './basic-right' import Placement from './placement' import UserProfile from './user-profile' import MultiLevelDrawer from './multi-level-drawer' -import FromDrawer from './from-drawer' +import FormInDrawer from './form-in-drawer' // import CustomPaging from './customPaging' // import CustomArrows from './customArrows' @@ -50,7 +50,7 @@ export default { - + diff --git a/components/drawer/index.en-US.md b/components/drawer/index.en-US.md index a1ea3659ca..a944b2e94c 100644 --- a/components/drawer/index.en-US.md +++ b/components/drawer/index.en-US.md @@ -4,16 +4,16 @@ | -------- | ----------- | ---- | ------- | | closable | Whether a close (x) button is visible on top right of the Drawer dialog or not. | boolean | true | | destroyOnClose | Whether to unmount child components on closing drawer or not. | boolean | false | -| getContainer | Return the mounted node for Drawer. | HTMLElement \| `() => HTMLElement` \| selectors  | 'body' | +| getContainer | Return the mounted node for Drawer. | HTMLElement \| `() => HTMLElement` \| Selectors | 'body' | | mask | Whether to show mask or not. | Boolean | true | | maskClosable | Clicking on the mask (area outside the Drawer) to close the Drawer or not. | boolean | true | | 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 | | wrapClassName | The class name of the container of the Drawer dialog. | string | - | +| wrapStyle | The style of the container of the Drawer dialog. | object | - | | 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. | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' | diff --git a/components/drawer/index.jsx b/components/drawer/index.jsx index c422588a76..1a61ff9ec0 100644 --- a/components/drawer/index.jsx +++ b/components/drawer/index.jsx @@ -1,4 +1,4 @@ -import classNames from 'classnames' +import classnames from 'classnames' import VcDrawer from '../vc-drawer/src' import PropTypes from '../_util/vue-types' import BaseMixin from '../_util/BaseMixin' @@ -14,6 +14,7 @@ const Drawer = { maskClosable: PropTypes.bool.def(true), mask: PropTypes.bool.def(true), maskStyle: PropTypes.object, + wrapStyle: PropTypes.object, title: PropTypes.any, visible: PropTypes.bool, width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).def(256), @@ -22,7 +23,7 @@ const Drawer = { prefixCls: PropTypes.string.def('ant-drawer'), placement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']).def('right'), level: PropTypes.any.def(null), - wrapClassName: PropTypes.string, + wrapClassName: PropTypes.string, // not use class like react, vue will add class to root dom }, mixins: [BaseMixin], data () { @@ -106,7 +107,7 @@ const Drawer = { return null } this.destoryClose = false - const { placement, bodyStyle } = this.$props + const { placement } = this.$props const containerStyle = placement === 'left' || placement === 'right' ? { @@ -156,26 +157,22 @@ const Drawer = { > {header} {closer} -
    +
    {this.$slots.default}
    ) }, getRcDrawerStyle () { - const { zIndex, placement, maskStyle } = this.$props - return this.$data._push - ? { - ...maskStyle, - zIndex, - transform: this.getPushTransform(placement), - } - : { - ...maskStyle, - zIndex, - } + const { zIndex, placement, maskStyle, wrapStyle } = this.$props + const { _push: push } = this.$data + return { + ...maskStyle, + zIndex, + transform: push ? this.getPushTransform(placement) : undefined, + ...wrapStyle, + } }, - }, render () { const props = getOptionProps(this) @@ -195,16 +192,16 @@ const Drawer = { open: visible, showMask: props.mask, placement, - wrapClassName: classNames({ + className: classnames({ [wrapClassName]: !!wrapClassName, [haveMask]: !!haveMask, }), + wrapStyle: this.getRcDrawerStyle(), }, on: { maskClick: this.onMaskClick, ...this.$listeners, }, - style: this.getRcDrawerStyle(), } return ( HTMLElement` \| selectors  | 'body' | +| getContainer | 指定 Drawer 挂载的 HTML 节点 | HTMLElement \| `() => HTMLElement` \| Selectors | 'body' | | maskClosable | 点击蒙层是否允许关闭 | boolean | true | | mask | 是否展示遮罩 | Boolean | true | | maskStyle | 遮罩样式 | object | {} | | title | 标题 | string \| slot | - | | visible | Drawer 是否可见 | boolean | - | | wrapClassName | 对话框外层容器的类名 | string | - | +| wrapStyle | 对话框外层容器的`style` | object | - | | width | 宽度 | string \| number | 256 | | height | 高度, 在 `placement` 为 `top` 或 `bottom` 时使用 | string \| number | 256 | | zIndex | 设置 Drawer 的 `z-index` | Number | 1000 | diff --git a/components/drawer/style/drawer.less b/components/drawer/style/drawer.less index 6475c781c9..4288673bd9 100644 --- a/components/drawer/style/drawer.less +++ b/components/drawer/style/drawer.less @@ -1,6 +1,6 @@ -@import "../../style/themes/default"; +@import '../../style/themes/default'; -@dawer-prefix-cls: ~"@{ant-prefix}-drawer"; +@dawer-prefix-cls: ~'@{ant-prefix}-drawer'; .@{dawer-prefix-cls} { position: fixed; @@ -169,7 +169,7 @@ height: 0; opacity: 0; background-color: @modal-mask-bg; - filter: ~"alpha(opacity=50)"; + filter: ~'alpha(opacity=50)'; transition: opacity @animation-duration-slow linear, height 0s ease @animation-duration-slow; } &-open { diff --git a/components/drawer/style/index.less b/components/drawer/style/index.less index 40a49a53b2..a081a08ca7 100644 --- a/components/drawer/style/index.less +++ b/components/drawer/style/index.less @@ -1,3 +1,3 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; -@import "./drawer"; +@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 e1a1adcbba..46d62eb56c 100644 --- a/components/dropdown/__tests__/__snapshots__/demo.test.js.snap +++ b/components/dropdown/__tests__/__snapshots__/demo.test.js.snap @@ -14,10 +14,9 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
    -
    diff --git a/components/dropdown/__tests__/dropdown-button.test.js b/components/dropdown/__tests__/dropdown-button.test.js index 12cd3c37f4..083e7742de 100644 --- a/components/dropdown/__tests__/dropdown-button.test.js +++ b/components/dropdown/__tests__/dropdown-button.test.js @@ -1,5 +1,6 @@ import { mount } from '@vue/test-utils' import Dropdown from '..' +import Menu from '../../menu' describe('DropdownButton', () => { it('pass appropriate props to Dropdown', () => { @@ -26,7 +27,17 @@ describe('DropdownButton', () => { }) it('don\'t pass visible to Dropdown if it\'s not exits', () => { - const wrapper = mount(Dropdown.Button) + const wrapper = mount({ + render () { + return ( + + foo + } + /> + ) + }, + }) const dropdownProps = wrapper.find({ name: 'ADropdown' }).props() expect('visible' in dropdownProps).toBe(false) diff --git a/components/dropdown/dropdown-button.jsx b/components/dropdown/dropdown-button.jsx index 85aa140d6a..908bfdd5f1 100644 --- a/components/dropdown/dropdown-button.jsx +++ b/components/dropdown/dropdown-button.jsx @@ -34,6 +34,9 @@ export default { prop: 'visible', event: 'visibleChange', }, + inject: { + configProvider: { default: {}}, + }, render () { const { type, disabled, htmlType, @@ -41,14 +44,14 @@ export default { visible, placement, getPopupContainer, ...restProps } = this.$props - + const { getPopupContainer: getContextPopupContainer } = this.configProvider const dropdownProps = { props: { align, disabled, trigger: disabled ? [] : trigger, placement, - getPopupContainer, + getPopupContainer: getPopupContainer || getContextPopupContainer, }, on: { visibleChange: this.onVisibleChange, diff --git a/components/dropdown/dropdown.jsx b/components/dropdown/dropdown.jsx index 84b012d3be..e5659b093f 100644 --- a/components/dropdown/dropdown.jsx +++ b/components/dropdown/dropdown.jsx @@ -21,6 +21,9 @@ const Dropdown = { prop: 'visible', event: 'visibleChange', }, + inject: { + configProvider: { default: {}}, + }, methods: { getTransitionName () { const { placement = '', transitionName } = this.$props @@ -35,7 +38,15 @@ const Dropdown = { }, render () { - const { $slots, prefixCls, trigger, disabled, $listeners } = this + const { $slots, $listeners } = this + const props = getOptionProps(this) + const { + prefixCls, + trigger, + disabled, + getPopupContainer, + } = props + const { getPopupContainer: getContextPopupContainer } = this.configProvider const dropdownTrigger = cloneElement($slots.default, { class: `${prefixCls}-trigger`, disabled, @@ -68,7 +79,8 @@ const Dropdown = { const dropdownProps = { props: { alignPoint, - ...getOptionProps(this), + ...props, + getPopupContainer: getPopupContainer || getContextPopupContainer, transitionName: this.getTransitionName(), trigger: triggerActions, }, diff --git a/components/dropdown/getDropdownProps.js b/components/dropdown/getDropdownProps.js index 93b0391e92..e03f6ceb41 100644 --- a/components/dropdown/getDropdownProps.js +++ b/components/dropdown/getDropdownProps.js @@ -9,5 +9,9 @@ export default () => ({ prefixCls: PropTypes.string, transitionName: PropTypes.string, placement: PropTypes.oneOf(['topLeft', 'topCenter', 'topRight', 'bottomLeft', 'bottomCenter', 'bottomRight']), + overlayClassName: PropTypes.string, + overlayStyle: PropTypes.object, forceRender: PropTypes.bool, + mouseEnterDelay: PropTypes.number, + mouseLeaveDelay: PropTypes.number, }) diff --git a/components/dropdown/index.en-US.md b/components/dropdown/index.en-US.md index f6d3885c50..059bc28cf4 100644 --- a/components/dropdown/index.en-US.md +++ b/components/dropdown/index.en-US.md @@ -7,6 +7,8 @@ | disabled | whether the dropdown menu is disabled | boolean | - | | getPopupContainer | to set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` | | overlay(slot) | the dropdown menu | [Menu](/ant-design-vue/components/menu) | - | +| overlayClassName | Class name of the dropdown root element | string | - | +| overlayStyle | Style of the dropdown root element | object | - | | placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` | | trigger | the trigger mode which executes the drop-down action | Array<`click`\|`hover`\|`contextmenu`> | `['hover']` | | visible(v-model) | whether the dropdown menu is visible | boolean | - | diff --git a/components/dropdown/index.zh-CN.md b/components/dropdown/index.zh-CN.md index 0c618f3d35..ef9ebc5ba1 100644 --- a/components/dropdown/index.zh-CN.md +++ b/components/dropdown/index.zh-CN.md @@ -7,6 +7,8 @@ | disabled | 菜单是否禁用 | boolean | - | | getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | `() => document.body` | | overlay(slot) | 菜单 | [Menu](/ant-design-vue/components/menu-cn) | - | +| overlayClassName | 下拉根元素的类名称 | string | - | +| overlayStyle | 下拉根元素的样式 | object | - | | placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` | | trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextmenu`> | `['hover']` | | visible(v-model) | 菜单是否显示 | boolean | - | diff --git a/components/dropdown/style/index.less b/components/dropdown/style/index.less index ec0e955b09..19cfa8eb12 100644 --- a/components/dropdown/style/index.less +++ b/components/dropdown/style/index.less @@ -1,7 +1,7 @@ -@import "../../style/themes/default"; -@import "../../style/mixins/index"; +@import '../../style/themes/default'; +@import '../../style/mixins/index'; -@dropdown-prefix-cls: ~"@{ant-prefix}-dropdown"; +@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown'; .@{dropdown-prefix-cls} { .reset-component; @@ -11,6 +11,16 @@ z-index: @zindex-dropdown; display: block; + &:before { + position: absolute; + top: -7px; + left: -7px; + right: 0; + bottom: -7px; + content: ' '; + opacity: 0.0001; + } + &-wrap { position: relative; @@ -19,7 +29,7 @@ } .@{iconfont-css-prefix}-down:before { - transition: transform .2s; + transition: transform 0.2s; } } @@ -45,11 +55,12 @@ border-radius: @border-radius-base; box-shadow: @box-shadow-base; background-clip: padding-box; + -webkit-transform: translate3d(0, 0, 0); &-item-group-title { color: @text-color-secondary; padding: 5px @control-padding-horizontal; - transition: all .3s; + transition: all 0.3s; } &-submenu-popup { @@ -71,7 +82,7 @@ color: @text-color; white-space: nowrap; cursor: pointer; - transition: all .3s; + transition: all 0.3s; line-height: 22px; > .anticon:first-child { @@ -84,7 +95,7 @@ display: block; padding: 5px @control-padding-horizontal; margin: -5px -@control-padding-horizontal; - transition: all .3s; + transition: all 0.3s; &:focus { text-decoration: none; } @@ -187,7 +198,7 @@ .@{dropdown-prefix-cls}-trigger, .@{dropdown-prefix-cls}-link { - > .@{iconfont-css-prefix}:not(.@{iconfont-css-prefix}-ellipsis) { + > .@{iconfont-css-prefix}.@{iconfont-css-prefix}-down { .iconfont-size-under-12px(10px); } } @@ -199,7 +210,7 @@ padding-left: @padding-xs; padding-right: @padding-xs; } - .@{iconfont-css-prefix}:not(.@{iconfont-css-prefix}-ellipsis) { + .@{iconfont-css-prefix}.@{iconfont-css-prefix}-down { .iconfont-size-under-12px(10px); } } diff --git a/components/form/Form.jsx b/components/form/Form.jsx index 1406fb800e..8c5c7a5924 100755 --- a/components/form/Form.jsx +++ b/components/form/Form.jsx @@ -112,6 +112,8 @@ export const ValidationRule = { // normalize?: (value: any, prevValue: any, allValues: any) => any; // /** Whether stop validate on first rule of error for this field. */ // validateFirst?: boolean; +// /** 是否一直保留子节点的信息 */ +// preserve?: boolean; // }; const Form = { diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap index aae9eb7c6c..f6e2d75b70 100644 --- a/components/form/__tests__/__snapshots__/demo.test.js.snap +++ b/components/form/__tests__/__snapshots__/demo.test.js.snap @@ -129,7 +129,7 @@ exports[`renders ./components/form/demo/coordinated.vue correctly 1`] = `
    -
    Select a option and change input text above
    +
    Select a option and change input text above
    @@ -169,8 +169,7 @@ exports[`renders ./components/form/demo/dynamic-form-item.vue correctly 1`] = `
    -
    +
    @@ -371,7 +370,7 @@ exports[`renders ./components/form/demo/register.vue correctly 1`] = `
    -
    Zhejiang / Hangzhou / West Lake
    Zhejiang / Hangzhou / West Lake
    -
    +86
    +
    +86
    @@ -392,10 +391,10 @@ exports[`renders ./components/form/demo/register.vue correctly 1`] = `
    -