diff --git a/build/config.js b/build/config.js index 7672cf990..8d2a3a5ee 100644 --- a/build/config.js +++ b/build/config.js @@ -1,5 +1,5 @@ module.exports = { dev: { - componentName: 'checkbox', // dev components + componentName: 'config-provider', // dev components }, }; diff --git a/components/_util/wave.jsx b/components/_util/wave.jsx index bc073d67b..ae7776204 100644 --- a/components/_util/wave.jsx +++ b/components/_util/wave.jsx @@ -162,7 +162,7 @@ export default { render() { if (this.configProvider.csp) { - this.csp = csp; + this.csp = this.configProvider.csp; } return this.$slots.default && this.$slots.default[0]; }, diff --git a/components/config-provider/__tests__/index.test.js b/components/config-provider/__tests__/index.test.js new file mode 100644 index 000000000..7e0dd49e8 --- /dev/null +++ b/components/config-provider/__tests__/index.test.js @@ -0,0 +1,44 @@ +import { mount } from '@vue/test-utils'; +import ConfigProvider from '..'; +import Button from '../../button'; +import mountTest from '../../../tests/shared/mountTest'; + +describe('ConfigProvider', () => { + mountTest({ + render() { + return ( + +
+ + ); + }, + }); + + it('Content Security Policy', () => { + const csp = { nonce: 'test-antd' }; + const wrapper = mount({ + render() { + return ( + + + + ); + }, + }); + + expect(wrapper.find({ name: 'AButton' }).text()).toBe('确定'); + }); +}); diff --git a/components/config-provider/demo/index.vue b/components/config-provider/demo/index.vue index 49b712e2f..4f4761273 100644 --- a/components/config-provider/demo/index.vue +++ b/components/config-provider/demo/index.vue @@ -1,4 +1,5 @@ + +``` diff --git a/components/config-provider/empty.svg b/components/config-provider/empty.svg deleted file mode 100644 index 0ce1dcebc..000000000 --- a/components/config-provider/empty.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/components/config-provider/index.en-US.md b/components/config-provider/index.en-US.md index b61912ec4..c3f4859cf 100644 --- a/components/config-provider/index.en-US.md +++ b/components/config-provider/index.en-US.md @@ -25,7 +25,7 @@ This component provides a configuration to all Vue components underneath itself ### Content Security Policy -Some component use dynamic style to support wave effect. You can config `csp` prop if Content Security Policy (CSP) is enabled: +Some components use dynamic style to support wave effect. You can config `csp` prop if Content Security Policy (CSP) is enabled: ```html @@ -35,10 +35,36 @@ Some component use dynamic style to support wave effect. You can config `csp` pr ## API -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| autoInsertSpaceInButton | Set `false` to remove space between 2 chinese characters on Button | boolean | true | -| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | -| renderEmpty | set empty content of components. Ref [Empty](/components/empty/) | slot-scope \| Function(componentName: string): ReactNode | - | -| getPopupContainer | to set the container of the popup element. The default is to create a `div` element in `body`. | Function(triggerNode, dialogContext) | `() => document.body` | -| prefixCls | set prefix class | string | ant | +| Property | Description | Type | Default | Version | +| --- | --- | --- | --- | --- | +| autoInsertSpaceInButton | Set `false` to remove space between 2 chinese characters on Button | boolean | true | | +| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | | +| renderEmpty | set empty content of components. Ref [Empty](/components/empty/) | slot-scope \| Function(componentName: string): ReactNode | - | | +| getPopupContainer | to set the container of the popup element. The default is to create a `div` element in `body`. | Function(triggerNode, dialogContext) | `() => document.body` | | +| locale | language package setting, you can find the packages in [antd/es/locale](http://unpkg.com/ant-design-vue/es/locale/) | object | - | 1.5.0 | +| prefixCls | set prefix class | string | ant | | +| pageHeader | Unify the ghost of pageHeader ,Ref [pageHeader](<(/components/page-header)> | { ghost:boolean } | 'true' | 1.5.0 | + +## FAQ + +#### Does the locale problem still exist in DatePicker even if ConfigProvider `locale` is used? + +Please make sure you set moment locale by `moment.locale('zh-cn')` or that you don't have two different versions of moment. + +#### Modal throw error when setting `getPopupContainer`? + +When you config `getPopupContainer` to parentNode globally, Modal will throw error of `triggerNode is undefined` because it did not have a triggerNode. + +```diff + triggerNode.parentNode} ++ getPopupContainer={node => { ++ if (node) { ++ return node.parentNode; ++ } ++ return document.body; ++ }} + > + + +``` diff --git a/components/config-provider/index.jsx b/components/config-provider/index.jsx index 062b7bf92..1083f40f9 100644 --- a/components/config-provider/index.jsx +++ b/components/config-provider/index.jsx @@ -3,11 +3,13 @@ import PropTypes from '../_util/vue-types'; import { filterEmpty, getComponentFromProp } from '../_util/props-util'; import defaultRenderEmpty from './renderEmpty'; import Base from '../base'; +import LocaleProvider, { ANT_MARK } from '../locale-provider'; +import LocaleReceiver from '../locale-provider/LocaleReceiver'; function getWatch(keys = []) { const watch = {}; keys.forEach(k => { - watch[k] = function() { + watch[k] = function(value) { this._proxyVm._data[k] = value; }; }); @@ -22,6 +24,8 @@ const ConfigProvider = { renderEmpty: PropTypes.func, csp: PropTypes.object, autoInsertSpaceInButton: PropTypes.bool, + locale: PropTypes.object, + pageHeader: PropTypes.object, }, provide() { const _self = this; @@ -39,7 +43,7 @@ const ConfigProvider = { }; }, watch: { - ...getWatch(['prefixCls', 'csp', 'autoInsertSpaceInButton']), + ...getWatch(['prefixCls', 'csp', 'autoInsertSpaceInButton', 'locale', 'pageHeader']), }, methods: { renderEmptyComponent(h, name) { @@ -52,9 +56,21 @@ const ConfigProvider = { if (customizePrefixCls) return customizePrefixCls; return suffixCls ? `${prefixCls}-${suffixCls}` : prefixCls; }, + renderProvider(legacyLocale) { + return ( + + {this.$slots.default ? filterEmpty(this.$slots.default)[0] : null} + + ); + }, }, + render() { - return this.$slots.default ? filterEmpty(this.$slots.default)[0] : null; + return ( + this.renderProvider(legacyLocale) }} + /> + ); }, }; diff --git a/components/config-provider/index.zh-CN.md b/components/config-provider/index.zh-CN.md index 67037efd8..776a77b44 100644 --- a/components/config-provider/index.zh-CN.md +++ b/components/config-provider/index.zh-CN.md @@ -35,10 +35,35 @@ ConfigProvider 使用 Vue 的 [provide / inject](https://vuejs.org/v2/api/#provi ## API -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| autoInsertSpaceInButton | 设置为 `false` 时,移除按钮中 2 个汉字之间的空格 | boolean | true | -| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | -| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty/) | slot-scope \| Function(componentName: string): VNode | - | -| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | Function(triggerNode, dialogContext) | () => document.body | -| prefixCls | 设置统一样式前缀 | string | ant | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| autoInsertSpaceInButton | 设置为 `false` 时,移除按钮中 2 个汉字之间的空格 | boolean | true | | +| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | | +| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty/) | slot-scope \| Function(componentName: string): VNode | - | | +| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | Function(triggerNode, dialogContext) | () => document.body | | +| locale | 语言包配置,语言包可到 [antd/es/locale](http://unpkg.com/antd/es/locale/) 目录下寻找 | object | - | 1.5.0 | +| pageHeader | 统一设置 pageHeader 的 ghost,参考 [pageHeader](<(/components/page-header)>) | { ghost: boolean } | 'true' | 1.5.0 | + +## FAQ + +#### 为什么我使用了 ConfigProvider `locale`,时间类组件的国际化还有问题? + +请检查是否设置了 `moment.locale('zh-cn')`,或者是否有两个版本的 moment 共存。 + +#### 配置 `getPopupContainer` 导致 Modal 报错? + +当如下全局设置 `getPopupContainer` 为触发节点的 parentNode 时,由于 Modal 的用法不存在 `triggerNode`,这样会导致 `triggerNode is undefined` 的报错,需要增加一个判断条件。 + +```diff + triggerNode.parentNode} ++ getPopupContainer={node => { ++ if (node) { ++ return node.parentNode; ++ } ++ return document.body; ++ }} + > + + +``` diff --git a/components/config-provider/renderEmpty.jsx b/components/config-provider/renderEmpty.jsx index 275a67d9b..b0158acd8 100644 --- a/components/config-provider/renderEmpty.jsx +++ b/components/config-provider/renderEmpty.jsx @@ -1,6 +1,5 @@ import PropTypes from '../_util/vue-types'; import Empty from '../empty'; -import emptyImg from './empty.svg'; import { ConfigConsumerProps } from './'; const RenderEmpty = { @@ -19,13 +18,14 @@ const RenderEmpty = { switch (componentName) { case 'Table': case 'List': - return ; + return ; case 'Select': case 'TreeSelect': case 'Cascader': case 'Transfer': - return ; + case 'Mentions': + return ; default: return ; diff --git a/components/locale-provider/LocaleReceiver.jsx b/components/locale-provider/LocaleReceiver.jsx index 89117c45f..2d659ce94 100644 --- a/components/locale-provider/LocaleReceiver.jsx +++ b/components/locale-provider/LocaleReceiver.jsx @@ -37,6 +37,7 @@ export default { render() { const { $scopedSlots } = this; const children = this.children || $scopedSlots.default; - return children(this.getLocale(), this.getLocaleCode()); + const { antLocale } = this.localeData; + return children(this.getLocale(), this.getLocaleCode(), antLocale); }, }; diff --git a/components/locale-provider/index.jsx b/components/locale-provider/index.jsx index 52672225c..62c087455 100644 --- a/components/locale-provider/index.jsx +++ b/components/locale-provider/index.jsx @@ -3,6 +3,7 @@ import * as moment from 'moment'; import interopDefault from '../_util/interopDefault'; import { changeConfirmLocale } from '../modal/locale'; import Base from '../base'; +import warning from '../_util/warning'; // export interface Locale { // locale: string; // Pagination?: Object; @@ -16,7 +17,7 @@ import Base from '../base'; // Select?: Object; // Upload?: Object; // } - +export const ANT_MARK = 'internalMark'; function setMomentLocale(locale) { if (locale && locale.locale) { interopDefault(moment).locale(locale.locale); @@ -29,8 +30,14 @@ const LocaleProvider = { name: 'ALocaleProvider', props: { locale: PropTypes.object.def({}), + _ANT_MARK__: PropTypes.string, }, data() { + warning( + this._ANT_MARK__ === ANT_MARK, + 'LocaleProvider', + '`LocaleProvider` is deprecated. Please use `locale` with `ConfigProvider` instead', + ); return { antLocale: { ...this.locale, @@ -50,6 +57,7 @@ const LocaleProvider = { exist: true, }; setMomentLocale(val); + changeConfirmLocale(val && val.Modal); }, }, created() { @@ -57,10 +65,6 @@ const LocaleProvider = { setMomentLocale(locale); changeConfirmLocale(locale && locale.Modal); }, - updated() { - const { locale } = this; - changeConfirmLocale(locale && locale.Modal); - }, beforeDestroy() { changeConfirmLocale(); },