merge master

This commit is contained in:
zombiej 2019-08-06 17:46:53 +08:00
commit b30dc1c3bc
356 changed files with 23695 additions and 6259 deletions

View File

@ -1,5 +1,12 @@
const eslintrc = {
extends: ['airbnb', 'prettier', 'plugin:jest/recommended'],
extends: [
'airbnb',
'prettier',
'plugin:jest/recommended',
'plugin:react/recommended',
'plugin:import/typescript',
'prettier/react',
],
env: {
browser: true,
node: true,
@ -7,8 +14,22 @@ const eslintrc = {
jest: true,
es6: true,
},
parser: 'babel-eslint',
plugins: ['markdown', 'react', 'babel', 'jest'],
settings: {
react: {
version: '16.8',
},
},
parser: '@typescript-eslint/parser',
plugins: ['markdown', 'react', 'babel', 'jest', '@typescript-eslint'],
// https://github.com/typescript-eslint/typescript-eslint/issues/46#issuecomment-470486034
overrides: [
{
files: ['*.tsx'],
rules: {
'@typescript-eslint/no-unused-vars': [2, { args: 'none' }],
},
},
],
rules: {
'react/jsx-one-expression-per-line': 0,
'react/prop-types': 0,
@ -29,12 +50,34 @@ const eslintrc = {
],
},
],
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.md'] }],
'jsx-a11y/no-static-element-interactions': 0,
'jsx-a11y/anchor-has-content': 0,
'jsx-a11y/click-events-have-key-events': 0,
'jsx-a11y/anchor-is-valid': 0,
'comma-dangle': ['error', 'always-multiline'],
'react/jsx-filename-extension': 0,
'prefer-destructuring': 0, // TODO: remove later
'consistent-return': 0, // TODO: remove later
'no-return-assign': 0, // TODO: remove later
'no-param-reassign': 0, // TODO: remove later
'react/destructuring-assignment': 0, // TODO: remove later
'react/no-did-update-set-state': 0, // TODO: remove later
'react/require-default-props': 0,
'react/default-props-match-prop-types': 0,
'import/no-cycle': 0,
'react/no-find-dom-node': 0,
'no-underscore-dangle': 0,
// label-has-for has been deprecated
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md
'jsx-a11y/label-has-for': 0,
// for (let i = 0; i < len; i++)
'no-plusplus': 0,
// https://eslint.org/docs/rules/no-continue
// labeledLoop is conflicted with `eslint . --fix`
'no-continue': 0,
'react/display-name': 0,
// ban this for Number.isNaN needs polyfill
'no-restricted-globals': 0,
},
};
@ -56,11 +99,6 @@ if (process.env.RUN_ENV === 'DEMO') {
'react/destructuring-assignment': 0,
'react/no-multi-comp': 0,
'jsx-a11y/href-no-hash': 0,
'prefer-destructuring': 0, // TODO: remove later
'max-len': 0, // TODO: remove later
'consistent-return': 0, // TODO: remove later
'no-return-assign': 0, // TODO: remove later
'no-param-reassign': 0, // TODO: remove later
'import/no-extraneous-dependencies': 0,
});
}

View File

@ -20,10 +20,10 @@ module.exports = {
},
testPathIgnorePatterns: ['/node_modules/', 'dekko', 'node'],
transform: {
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.md$': './node_modules/antd-tools/lib/jest/demoPreprocessor',
'\\.(jpg|png|gif|svg)$': './node_modules/antd-tools/lib/jest/imagePreprocessor',
'\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
'\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
},
testRegex: `${libDir === 'dist' ? 'demo' : '.*'}\\.test\\.js$`,
collectCoverageFrom: [

View File

@ -6,10 +6,10 @@ module.exports = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
moduleNameMapper,
transform: {
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.md$': './node_modules/antd-tools/lib/jest/demoPreprocessor',
'\\.(jpg|png|gif|svg)$': './node_modules/antd-tools/lib/jest/imagePreprocessor',
'\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
'\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor',
'\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor',
'\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor',
},
testRegex: 'demo\\.test\\.js$',
testEnvironment: 'node',

View File

@ -374,6 +374,7 @@ Shun <polytechnics.shun@gmail.com>
Shuvalov Anton <anton@shuvalov.info>
SimaQ <sima.zhang1990@gmail.com>
Simo Aleksandrov <simo3003@me.com>
Sivaraj S <sivaraj@sdev.in>
Spencer <spjy@hawaii.edu>
Stephen Esser <Stephen.Esser@gmail.com>
Subroto <shub1493biswas@gmail.com>

View File

@ -15,8 +15,61 @@ timeline: true
---
## 3.21.2
`2019-08-06`
- 🐞 Fix `React does not recognize the noStyle prop on a DOM element` warning. [#18088](https://github.com/ant-design/ant-design/pull/18088)
- 🐞 Fix Input `prefix` & `suffix` not align with text. [#18097](https://github.com/ant-design/ant-design/pull/18097)
- 🐞 Fix ConfigProvider nest in LocaleProvider make `locale` not work. [#18105](https://github.com/ant-design/ant-design/pull/18105)
## 3.21.1
`2019-08-05`
- 🐞 Fix ConfigProvider crash with multiple children. [#18075](https://github.com/ant-design/ant-design/pull/18075)
## 3.21.0
`2019-08-04`
- 🌟 Breadcrumb adds `Separator` component. [#17873](https://github.com/ant-design/ant-design/pull/17873) [@long-zhuge](https://github.com/long-zhuge)
- 🌟 Descriptions adds `colon` props. [#17560](https://github.com/ant-design/ant-design/pull/17560) [@hengkx](https://github.com/hengkx)
- 🌟 Rotate zero when Sider triggers in right mode. [#18043](https://github.com/ant-design/ant-design/pull/18043) [@kagawagao](https://github.com/kagawagao)
- 🌟 Table add `getPopupContainer` props. [#17806](https://github.com/ant-design/ant-design/pull/17806)
- 🌟 Add new color `gray` for Timeline.Item for unfinished or disabled status. [#17731](https://github.com/ant-design/ant-design/pull/17731)
- 🌟 Upload adds `transformFile` to support transforming file before file uploading. [#18009](https://github.com/ant-design/ant-design/pull/18009) [@lijinke666](https://github.com/lijinke666)
- 🐞 Fix ConfigProvider `getPopupContainer` not working in Table. [#17806](https://github.com/ant-design/ant-design/pull/17806)
- 🐞 Fix Statistic font not align with global font. [#18044](https://github.com/ant-design/ant-design/pull/18044)
- 🐞 Fix `Form.Item` label replace regexp. [#17985](https://github.com/ant-design/ant-design/pull/17985) [@shaodahong](https://github.com/shaodahong)
- 🐞 Fix Select search style. [#17760](https://github.com/ant-design/ant-design/pull/17760) [@chenyizhongx](https://github.com/chenyizhongx)
- 🐞 Fix DatePicker style bug when `mode` is decade. [#17887](https://github.com/ant-design/ant-design/pull/17887) [@xrkffgg](https://github.com/xrkffgg)
- 🐞 Fix wave effect performance of Button and other related component. [#17945](https://github.com/ant-design/ant-design/pull/17945)
- 🐞 Fix Tabs `tabBarExtraContent` align issue. [#17969](https://github.com/ant-design/ant-design/pull/17969)
- 🐞 Fix Tabs error when `type` is `editable-card` and child component is false. [#17965](https://github.com/ant-design/ant-design/pull/17965) [@oldturkey](https://github.com/oldturkey)
- 🐞 Fix Input align issue of `clearIcon` and `suffix` again. [#17684](https://github.com/ant-design/ant-design/pull/17684) [@LilyWakana](https://github.com/LilyWakana)
- 🐞 Remove `a` tag in Alert's close tag. [#17872](https://github.com/ant-design/ant-design/pull/17872) [@geograous](https://github.com/geograous)
- 💄 Unified drawer and modal `mask` opacity. [#17943](https://github.com/ant-design/ant-design/pull/17943)
- 💄 Optimize RangePicker focus style. [#17983](https://github.com/ant-design/ant-design/pull/17983)
- 💄 Tag now will be rendered as a `span`. [#17971](https://github.com/ant-design/ant-design/pull/17971)
- 💄 Enhance accessibility of Table expanded icon. [#17781](https://github.com/ant-design/ant-design/pull/17781)
- 💄 Merge LocaleProvider into ConfigProvider. [#17816](https://github.com/ant-design/ant-design/pull/17816)
- 💄 Add some less variables. [#17976](https://github.com/ant-design/ant-design/pull/17976) [@Yangzhedi](https://github.com/Yangzhedi) [#17613](https://github.com/ant-design/ant-design/pull/17613) [@alxkosov](https://github.com/alxkosov):
- `@table-footer-bg`
- `@table-footer-color`
- `@menu-icon-size`
- `@menu-icon-size-lg`
- 🇲🇾 Add locale Malay. [#17546](https://github.com/ant-design/ant-design/pull/17546) [@austin-krave](https://github.com/austin-krave)
- 🇸🇪 Add Swedish translation for Typography (Text) component. [#17858](https://github.com/ant-design/ant-design/pull/17858) [@Malven](https://github.com/Malven)
- 🇫🇷 Add French translation for Typography (Text) component. [#17418](https://github.com/ant-design/ant-design/pull/17418) [@Clafouti](https://github.com/Clafouti)
- 🏴 Add Tamil spanish translations. [#17903](https://github.com/ant-design/ant-design/pull/17903) [@sivaraj-dev](https://github.com/sivaraj-dev)
- TypeScript
- 🐞 Fix DatePicker `onChange` type definition. [#17955](https://github.com/ant-design/ant-design/pull/17955) [@haimrait](https://github.com/haimrait)
## 3.20.7
`2019-07-26`
- 🐞 Fix Upload can not click in Form.Item. [#17897](https://github.com/ant-design/ant-design/pull/17897)
## 3.20.6
@ -2022,13 +2075,13 @@ We provide a [migration tool](https://github.com/ant-design/antd-migration-helpe
- Improved global reset style, if you encounter style problem after upgrading, you can try import our v2 compatible style.
```javascript
import 'antd/lib/style/v2-compatible-reset';
import 'antd/es/style/v2-compatible-reset';
```
Or use less
```less
@import '~antd/lib/style/v2-compatible-reset.less';
@import '~antd/es/style/v2-compatible-reset.less';
```
- Since we changed default locale to en_US, LocalProvider is not required any more for English users.

View File

@ -15,8 +15,61 @@ timeline: true
---
## 3.21.2
`2019-08-06`
- 🐞 修复 `React does not recognize the noStyle prop on a DOM element` 的问题。[#18088](https://github.com/ant-design/ant-design/pull/18088)
- 🐞 修复 Input `prefix` & `suffix` 文本没对齐的问题。[#18097](https://github.com/ant-design/ant-design/pull/18097)
- 🐞 修复 ConfigProvider 嵌套于 LocaleProvider 内时 `locale` 无效的问题。[#18105](https://github.com/ant-design/ant-design/pull/18105)
## 3.21.1
`2019-08-05`
- 🐞 修复 ConfigProvider 存在多个子节点崩溃的问题。[#18075](https://github.com/ant-design/ant-design/pull/18075)
## 3.21.0
`2019-08-04`
- 🌟 新增 `Breadcrumb.Separator` 组件,可进行 `separator` 自定义。[#17873](https://github.com/ant-design/ant-design/issues/17873) [@long-zhuge](https://github.com/long-zhuge)
- 🌟 Descriptions 新增 `colon` 属性。[#17560](https://github.com/ant-design/ant-design/pull/17560) [@hengkx](https://github.com/hengkx)
- 🌟 当 Sider 在右边时,翻转 `trigger` 方向。[#18043](https://github.com/ant-design/ant-design/pull/18043) [@kagawagao](https://github.com/kagawagao)
- 🌟 Table 新增 `getPopupContainer` 属性用于设置表格内的各类浮层渲染节点。[#17806](https://github.com/ant-design/ant-design/pull/17806)
- 🌟 Timeline.Item 新增 `gray` 色彩类型,可用于未完成或失效状态。[#17731](https://github.com/ant-design/ant-design/pull/17731)
- 🌟 Upload 新增 `transformFile` 支持上传之前转换文件。[#18009](https://github.com/ant-design/ant-design/pull/18009) [@lijinke666](https://github.com/lijinke666)
- 🐞 修复 ConfigProvider `getPopupContainer` 对 Table 不生效的问题。 [#17806](https://github.com/ant-design/ant-design/pull/17806)
- 🐞 修复 Statistic 字体与全局字体不一致的问题。[#18044](https://github.com/ant-design/ant-design/pull/18044)
- 🐞 修复 `Form.Item` label 正则替换问题。[#17985](https://github.com/ant-design/ant-design/pull/17985) [@shaodahong](https://github.com/shaodahong)
- 🐞 修复 Select 搜索框箭头样式问题。 [#17760](https://github.com/ant-design/ant-design/pull/17760) [@chenyizhongx](https://github.com/chenyizhongx)
- 🐞 修复 DatePicker 中选择 `mode` 为 decade 时border 样式 bug。[#17887](https://github.com/ant-design/ant-design/pull/17887) [@xrkffgg](https://github.com/xrkffgg)
- 🐞 修复 Button 以及相关组件的波纹性能问题。[#17945](https://github.com/ant-design/ant-design/pull/17945)
- 🐞 修复 Tabs `tabBarExtraContent` 不居中对齐的问题。[#17969](https://github.com/ant-design/ant-design/pull/17969)
- 🐞 修复 Tabs 在 `type``editable-card` 且子组件为 false 值时会报错的问题。[#17965](https://github.com/ant-design/ant-design/pull/17965) [@oldturkey](https://github.com/oldturkey)
- 🐞 再次修复 Input 内的清除图标和 `suffix` 对齐问题。[#17684](https://github.com/ant-design/ant-design/pull/17684) [@LilyWakana](https://github.com/LilyWakana)
- 🐞 移除 Alert 关闭标签中的 `a` 标签。[#17872](https://github.com/ant-design/ant-design/pull/17872) [@geograous](https://github.com/geograous)
- 💄 统一 Drawer 和 Modal 的 `mask` 透明度为 45%。[#17943](https://github.com/ant-design/ant-design/pull/17943)
- 💄 优化 RangePicker 当前选中样式,与 DatePicker 样式统一。[#17983](https://github.com/ant-design/ant-design/pull/17983)
- 💄 调整 Tag 的 html 标签为 `span`。[#17971](https://github.com/ant-design/ant-design/pull/17971)
- 💄 提升 Table 展开按钮的无障碍体验。[#17781](https://github.com/ant-design/ant-design/pull/17781)
- 💄 将 LocaleProvider 合并入 ConfigProvider。[#17816](https://github.com/ant-design/ant-design/pull/17816)
- 💄 增加 less 变量 [#17976](https://github.com/ant-design/ant-design/pull/17976) [@Yangzhedi](https://github.com/Yangzhedi) [#17613](https://github.com/ant-design/ant-design/pull/17613) [@alxkosov](https://github.com/alxkosov)
- `@table-footer-bg`
- `@table-footer-color`
- `@menu-icon-size`
- `@menu-icon-size-lg`
- 🇲🇾 新增马来语语言包。[#17546](https://github.com/ant-design/ant-design/pull/17546) [@austin-krave](https://github.com/austin-krave)
- 🇸🇪 新增 Typography 的瑞典语言翻译。[#17858](https://github.com/ant-design/ant-design/pull/17858) [@Malven](https://github.com/Malven)
- 🇫🇷 新增 Typography 的法语语言翻译。[#17418](https://github.com/ant-design/ant-design/pull/17418) [@Clafouti](https://github.com/Clafouti)
- 🏴 新增部分组件的泰米尔语语言翻译。[#17903](https://github.com/ant-design/ant-design/pull/17903) [@sivaraj-dev](https://github.com/sivaraj-dev)
- TypeScript
- 🐞 修复 DatePicker `onChange` 类型定义。[#17955](https://github.com/ant-design/ant-design/pull/17955) [@haimrait](https://github.com/haimrait)
## 3.20.7
`2019-07-26`
- 🐞 修复 Upload 在 Form.Item 中无法点击的问题。[#17897](https://github.com/ant-design/ant-design/pull/17897)
## 3.20.6
@ -2025,20 +2078,20 @@ timeline: true
- 优化了全局的重置样式,如果升级后你的全局样式有问题,可以引入我们提供的 2.x 兼容样式。
```javascript
import 'antd/lib/style/v2-compatible-reset';
import 'antd/es/style/v2-compatible-reset';
```
或者在 less 里引入
```less
@import '~antd/lib/style/v2-compatible-reset.less';
@import '~antd/es/style/v2-compatible-reset.less';
```
- 由于默认语言改为英文,如果你需要显示中文,现在需要配置 `LocalProvider`
```javascript
import { LocaleProvider } from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import zhCN from 'antd/es/locale/zh_CN';
ReactDOM.render(
<LocaleProvider locale={zhCN}>

View File

@ -10,7 +10,7 @@
An enterprise-class UI design language and React implementation.
[![Build Status](https://dev.azure.com/ant-design/ant-design/_apis/build/status/ant-design.ant-design?branchName=master)](https://dev.azure.com/ant-design/ant-design/_build/latest?definitionId=2?branchName=master) [![CircleCI branch](https://img.shields.io/circleci/project/github/ant-design/ant-design/master.svg?style=flat-square)](https://circleci.com/gh/ant-design/ant-design) [![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master) [![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd) [![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://npmjs.com/antd)
[![CircleCI branch](https://img.shields.io/circleci/project/github/ant-design/ant-design/master.svg?style=flat-square)](https://circleci.com/gh/ant-design/ant-design) [![Build Status](https://dev.azure.com/ant-design/ant-design/_apis/build/status/ant-design.ant-design?branchName=master)](https://dev.azure.com/ant-design/ant-design/_build/latest?definitionId=2?branchName=master) [![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master) [![](https://flat.badgen.net/npm/v/antd?icon=npm)](https://www.npmjs.com/package/antd) [![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://npmjs.com/antd)
[![Dependencies](https://img.shields.io/david/ant-design/ant-design.svg?style=flat-square)](https://david-dm.org/ant-design/ant-design) [![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design.svg?style=flat-square)](https://david-dm.org/ant-design/ant-design?type=dev) [![Total alerts](https://flat.badgen.net/lgtm/alerts/g/ant-design/ant-design)](https://lgtm.com/projects/g/ant-design/ant-design/alerts/) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fant-design%2Fant-design.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield) [![Issues need help](https://flat.badgen.net/github/label-issues/ant-design/ant-design/help%20wanted/open)](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)

View File

@ -27,7 +27,7 @@ const getCollapsedHeight: MotionFunc = () => ({ height: 0, opacity: 0 });
const getRealHeight: MotionFunc = node => ({ height: node.scrollHeight, opacity: 1 });
const getCurrentHeight: MotionFunc = node => ({ height: node.offsetHeight });
export const collapseMotion: Motion = {
const collapseMotion: Motion = {
motionName: 'ant-motion-collapse',
onAppearStart: getCollapsedHeight,
onEnterStart: getCollapsedHeight,
@ -36,3 +36,5 @@ export const collapseMotion: Motion = {
onLeaveStart: getCurrentHeight,
onLeaveActive: getCollapsedHeight,
};
export default collapseMotion;

View File

@ -26,6 +26,7 @@ export function throttleByAnimationFrameDecorator() {
return {
configurable: true,
get() {
// eslint-disable-next-line no-prototype-builtins
if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
return fn;
}

View File

@ -7,6 +7,7 @@ import KeyCode from 'rc-util/lib/KeyCode';
interface TransButtonProps extends React.HTMLAttributes<HTMLDivElement> {
onClick?: (e?: React.MouseEvent<HTMLDivElement>) => void;
noStyle?: boolean;
}
const inlineStyle: React.CSSProperties = {
@ -19,6 +20,7 @@ const inlineStyle: React.CSSProperties = {
class TransButton extends React.Component<TransButtonProps> {
div?: HTMLDivElement;
lastKeyCode?: number;
onKeyDown: React.KeyboardEventHandler<HTMLDivElement> = event => {
@ -53,16 +55,17 @@ class TransButton extends React.Component<TransButtonProps> {
}
render() {
const { style } = this.props;
const { style, noStyle, ...restProps } = this.props;
return (
<div
role="button"
tabIndex={0}
ref={this.setRef}
{...this.props}
{...restProps}
onKeyDown={this.onKeyDown}
onKeyUp={this.onKeyUp}
style={{ ...inlineStyle, ...style }}
style={{ ...(!noStyle ? inlineStyle : null), ...style }}
/>
);
}

View File

@ -1,6 +1,11 @@
import warning from 'warning';
const warned: Record<string, boolean> = {};
let warned: Record<string, boolean> = {};
export function resetWarned() {
warned = {};
}
export default (valid: boolean, component: string, message: string): void => {
if (!valid && !warned[message]) {
warning(false, `[antd: ${component}] ${message}`);

View File

@ -1,7 +1,7 @@
import * as React from 'react';
import { findDOMNode } from 'react-dom';
import TransitionEvents from 'css-animation/lib/Event';
import raf from '../_util/raf';
import raf from './raf';
import { ConfigConsumer, ConfigConsumerProps, CSPConfig } from '../config-provider';
let styleForPesudo: HTMLStyleElement | null;
@ -14,24 +14,49 @@ function isHidden(element: HTMLElement) {
return !element || element.offsetParent === null;
}
function isNotGrey(color: string) {
// eslint-disable-next-line no-useless-escape
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/);
if (match && match[1] && match[2] && match[3]) {
return !(match[1] === match[2] && match[2] === match[3]);
}
return true;
}
export default class Wave extends React.Component<{ insertExtraNode?: boolean }> {
private instance?: {
cancel: () => void;
};
private extraNode: HTMLDivElement;
private clickWaveTimeoutId: number;
private animationStartId: number;
private animationStart: boolean = false;
private destroy: boolean = false;
private csp?: CSPConfig;
isNotGrey(color: string) {
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/);
if (match && match[1] && match[2] && match[3]) {
return !(match[1] === match[2] && match[2] === match[3]);
componentDidMount() {
const node = findDOMNode(this) as HTMLElement;
if (!node || node.nodeType !== 1) {
return;
}
return true;
this.instance = this.bindAnimationEvent(node);
}
componentWillUnmount() {
if (this.instance) {
this.instance.cancel();
}
if (this.clickWaveTimeoutId) {
clearTimeout(this.clickWaveTimeoutId);
}
this.destroy = true;
}
onClick = (node: HTMLElement, waveColor: string) => {
@ -40,7 +65,7 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
}
const { insertExtraNode } = this.props;
this.extraNode = document.createElement('div');
const extraNode = this.extraNode;
const { extraNode } = this;
extraNode.className = 'ant-click-animating-node';
const attributeName = this.getAttributeName();
node.setAttribute(attributeName, 'true');
@ -50,7 +75,7 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
waveColor &&
waveColor !== '#ffffff' &&
waveColor !== 'rgb(255, 255, 255)' &&
this.isNotGrey(waveColor) &&
isNotGrey(waveColor) &&
!/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color
waveColor !== 'transparent'
) {
@ -75,6 +100,31 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
TransitionEvents.addEndEventListener(node, this.onTransitionEnd);
};
onTransitionStart = (e: AnimationEvent) => {
if (this.destroy) return;
const node = findDOMNode(this) as HTMLElement;
if (!e || e.target !== node) {
return;
}
if (!this.animationStart) {
this.resetEffect(node);
}
};
onTransitionEnd = (e: AnimationEvent) => {
if (!e || e.animationName !== 'fadeEffect') {
return;
}
this.resetEffect(e.target as HTMLElement);
};
getAttributeName() {
const { insertExtraNode } = this.props;
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
}
bindAnimationEvent = (node: HTMLElement) => {
if (
!node ||
@ -113,11 +163,6 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
};
};
getAttributeName() {
const { insertExtraNode } = this.props;
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
}
resetEffect(node: HTMLElement) {
if (!node || node === this.extraNode || !(node instanceof Element)) {
return;
@ -125,7 +170,11 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
const { insertExtraNode } = this.props;
const attributeName = this.getAttributeName();
node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
this.removeExtraStyleNode();
if (styleForPesudo) {
styleForPesudo.innerHTML = '';
}
if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
node.removeChild(this.extraNode);
}
@ -133,51 +182,6 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
TransitionEvents.removeEndEventListener(node, this.onTransitionEnd);
}
onTransitionStart = (e: AnimationEvent) => {
if (this.destroy) return;
const node = findDOMNode(this) as HTMLElement;
if (!e || e.target !== node) {
return;
}
if (!this.animationStart) {
this.resetEffect(node);
}
};
onTransitionEnd = (e: AnimationEvent) => {
if (!e || e.animationName !== 'fadeEffect') {
return;
}
this.resetEffect(e.target as HTMLElement);
};
removeExtraStyleNode() {
if (styleForPesudo) {
styleForPesudo.innerHTML = '';
}
}
componentDidMount() {
const node = findDOMNode(this) as HTMLElement;
if (!node || node.nodeType !== 1) {
return;
}
this.instance = this.bindAnimationEvent(node);
}
componentWillUnmount() {
if (this.instance) {
this.instance.cancel();
}
if (this.clickWaveTimeoutId) {
clearTimeout(this.clickWaveTimeoutId);
}
this.destroy = true;
}
renderWave = ({ csp }: ConfigConsumerProps) => {
const { children } = this.props;
this.csp = csp;

View File

@ -63,7 +63,9 @@ class Affix extends React.Component<AffixProps, AffixState> {
};
placeholderNode: HTMLDivElement;
fixedNode: HTMLDivElement;
private timeout: number;
// Event handler
@ -75,7 +77,7 @@ class Affix extends React.Component<AffixProps, AffixState> {
this.timeout = setTimeout(() => {
addObserveTarget(target(), this);
// Mock Event object.
this.updatePosition({} as Event);
this.updatePosition();
});
}
}
@ -93,7 +95,7 @@ class Affix extends React.Component<AffixProps, AffixState> {
if (newTarget) {
addObserveTarget(newTarget, this);
// Mock Event object.
this.updatePosition({} as Event);
this.updatePosition();
}
this.setState({ prevTarget: newTarget });
@ -103,7 +105,7 @@ class Affix extends React.Component<AffixProps, AffixState> {
prevProps.offsetTop !== this.props.offsetTop ||
prevProps.offsetBottom !== this.props.offsetBottom
) {
this.updatePosition({} as Event);
this.updatePosition();
}
this.measure();
@ -132,6 +134,7 @@ class Affix extends React.Component<AffixProps, AffixState> {
}
return offsetTop;
};
getOffsetBottom = () => {
return this.props.offsetBottom;
};
@ -145,60 +148,6 @@ class Affix extends React.Component<AffixProps, AffixState> {
};
// =================== Measure ===================
// Handle realign logic
@throttleByAnimationFrameDecorator()
updatePosition(event?: Event | null) {
this.prepareMeasure(event);
}
@throttleByAnimationFrameDecorator()
lazyUpdatePosition(event: Event) {
const { target } = this.props;
const { affixStyle } = this.state;
// Check position change before measure to make Safari smooth
if (target && affixStyle) {
const offsetTop = this.getOffsetTop();
const offsetBottom = this.getOffsetBottom();
const targetNode = target();
if (targetNode) {
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.placeholderNode);
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
if (
(fixedTop !== undefined && affixStyle.top === fixedTop) ||
(fixedBottom !== undefined && affixStyle.bottom === fixedBottom)
) {
return;
}
}
}
// Directly call prepare measure since it's already throttled.
this.prepareMeasure(event);
}
// @ts-ignore TS6133
prepareMeasure = (event?: Event | null) => {
// event param is used before. Keep compatible ts define here.
this.setState({
status: AffixStatus.Prepare,
affixStyle: undefined,
placeholderStyle: undefined,
});
// Test if `updatePosition` called
if (process.env.NODE_ENV === 'test') {
const { onTestUpdatePosition } = this.props as any;
if (onTestUpdatePosition) {
onTestUpdatePosition();
}
}
};
measure = () => {
const { status, lastAffix } = this.state;
const { target, onChange } = this.props;
@ -254,6 +203,60 @@ class Affix extends React.Component<AffixProps, AffixState> {
this.setState(newState as AffixState);
};
// @ts-ignore TS6133
prepareMeasure = () => {
// event param is used before. Keep compatible ts define here.
this.setState({
status: AffixStatus.Prepare,
affixStyle: undefined,
placeholderStyle: undefined,
});
// Test if `updatePosition` called
if (process.env.NODE_ENV === 'test') {
const { onTestUpdatePosition } = this.props as any;
if (onTestUpdatePosition) {
onTestUpdatePosition();
}
}
};
// Handle realign logic
@throttleByAnimationFrameDecorator()
updatePosition() {
this.prepareMeasure();
}
@throttleByAnimationFrameDecorator()
lazyUpdatePosition() {
const { target } = this.props;
const { affixStyle } = this.state;
// Check position change before measure to make Safari smooth
if (target && affixStyle) {
const offsetTop = this.getOffsetTop();
const offsetBottom = this.getOffsetBottom();
const targetNode = target();
if (targetNode) {
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.placeholderNode);
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
if (
(fixedTop !== undefined && affixStyle.top === fixedTop) ||
(fixedBottom !== undefined && affixStyle.bottom === fixedBottom)
) {
return;
}
}
}
// Directly call prepare measure since it's already throttled.
this.prepareMeasure();
}
// =================== Render ===================
renderAffix = ({ getPrefixCls }: ConfigConsumerProps) => {
const { affixStyle, placeholderStyle } = this.state;

View File

@ -74,9 +74,9 @@ export function addObserveTarget(target: HTMLElement | Window | null, affix: Aff
// Add listener
TRIGGER_EVENTS.forEach(eventName => {
entity!.eventHandlers[eventName] = addEventListener(target, eventName, (event: Event) => {
entity!.affixList.forEach(affix => {
affix.lazyUpdatePosition(event);
entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => {
entity!.affixList.forEach(targetAffix => {
targetAffix.lazyUpdatePosition();
});
});
});

View File

@ -69,6 +69,7 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
<span
class="ant-alert-close-icon"
role="button"
tabindex="0"
>
<i
aria-label="icon: close"
@ -174,6 +175,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
<span
class="ant-alert-close-icon"
role="button"
tabindex="0"
>
<i
aria-label="icon: close"
@ -213,6 +215,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
<span
class="ant-alert-close-icon"
role="button"
tabindex="0"
>
<i
aria-label="icon: close"
@ -254,6 +257,7 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
<span
class="ant-alert-close-icon"
role="button"
tabindex="0"
>
<span
class="ant-alert-close-text"
@ -909,6 +913,7 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
<span
class="ant-alert-close-icon"
role="button"
tabindex="0"
>
<i
aria-label="icon: close"

View File

@ -49,4 +49,19 @@ describe('Alert', () => {
expect(input.getAttribute('role')).toBe('status');
});
});
it('warning for props#iconType', () => {
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(
<Alert
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
type="warning"
iconType="up"
/>,
);
expect(warnSpy).toHaveBeenCalledWith(
'Warning: [antd: Alert] `iconType` is deprecated. Please use `icon` instead.',
);
warnSpy.mockRestore();
});
});

View File

@ -1,10 +1,11 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Animate from 'rc-animate';
import Icon, { ThemeType } from '../icon';
import classNames from 'classnames';
import Icon, { ThemeType } from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getDataOrAriaProps from '../_util/getDataOrAriaProps';
import warning from '../_util/warning';
function noop() {}
@ -41,10 +42,20 @@ export interface AlertState {
}
export default class Alert extends React.Component<AlertProps, AlertState> {
state: AlertState = {
closing: true,
closed: false,
};
constructor(props: AlertProps) {
super(props);
warning(
!('iconType' in props),
'Alert',
'`iconType` is deprecated. Please use `icon` instead.',
);
this.state = {
closing: true,
closed: false,
};
}
handleClose = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
@ -89,8 +100,6 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
type = banner && type === undefined ? 'warning' : type || 'info';
let iconTheme: ThemeType = 'filled';
// should we give a warning?
// warning(!iconType, `The property 'iconType' is deprecated. Use the property 'icon' instead.`);
if (!iconType) {
switch (type) {
case 'success':
@ -110,7 +119,7 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
}
// use outline icon in alert with description
if (!!description) {
if (description) {
iconTheme = 'outlined';
}
}
@ -134,7 +143,12 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
);
const closeIcon = closable ? (
<span role="button" onClick={this.handleClose} className={`${prefixCls}-close-icon`}>
<span
role="button"
onClick={this.handleClose}
className={`${prefixCls}-close-icon`}
tabIndex={0}
>
{closeText ? (
<span className={`${prefixCls}-close-text`}>{closeText}</span>
) : (

View File

@ -3,11 +3,11 @@ import * as ReactDOM from 'react-dom';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import raf from 'raf';
import Affix from '../affix';
import AnchorLink from './AnchorLink';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getScroll from '../_util/getScroll';
import raf from 'raf';
function getDefaultContainer() {
return window;
@ -145,11 +145,14 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
};
private inkNode: HTMLSpanElement;
// scroll scope's container
private scrollContainer: HTMLElement | Window;
private links: string[] = [];
private scrollEvent: any;
private animating: boolean;
private prefixCls?: string;
@ -181,12 +184,6 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
this.handleScroll();
}
componentWillUnmount() {
if (this.scrollEvent) {
this.scrollEvent.remove();
}
}
componentDidUpdate() {
if (this.scrollEvent) {
const { getContainer } = this.props as AnchorDefaultProps;
@ -201,28 +198,11 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
this.updateInk();
}
handleScroll = () => {
if (this.animating) {
return;
componentWillUnmount() {
if (this.scrollEvent) {
this.scrollEvent.remove();
}
const { activeLink } = this.state;
const { offsetTop, bounds } = this.props;
const currentActiveLink = this.getCurrentAnchor(offsetTop, bounds);
if (activeLink !== currentActiveLink) {
this.setState({
activeLink: currentActiveLink,
});
}
};
handleScrollTo = (link: string) => {
const { offsetTop, getContainer } = this.props as AnchorDefaultProps;
this.animating = true;
this.setState({ activeLink: link });
scrollTo(link, offsetTop, getContainer, () => {
this.animating = false;
});
};
}
getCurrentAnchor(offsetTop = 0, bounds = 5): string {
const activeLink = '';
@ -257,11 +237,38 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
return '';
}
saveInkNode = (node: HTMLSpanElement) => {
this.inkNode = node;
};
handleScroll = () => {
if (this.animating) {
return;
}
const { activeLink } = this.state;
const { offsetTop, bounds } = this.props;
const currentActiveLink = this.getCurrentAnchor(offsetTop, bounds);
if (activeLink !== currentActiveLink) {
this.setState({
activeLink: currentActiveLink,
});
}
};
handleScrollTo = (link: string) => {
const { offsetTop, getContainer } = this.props as AnchorDefaultProps;
this.animating = true;
this.setState({ activeLink: link });
scrollTo(link, offsetTop, getContainer, () => {
this.animating = false;
});
};
updateInk = () => {
if (typeof document === 'undefined') {
return;
}
const prefixCls = this.prefixCls;
const { prefixCls } = this;
const anchorNode = ReactDOM.findDOMNode(this) as Element;
const linkNode = anchorNode.getElementsByClassName(`${prefixCls}-link-title-active`)[0];
if (linkNode) {
@ -269,10 +276,6 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
}
};
saveInkNode = (node: HTMLSpanElement) => {
this.inkNode = node;
};
renderAnchor = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,

View File

@ -9,13 +9,19 @@ export default class InputElement extends React.Component<InputElementProps, any
private ele: HTMLInputElement;
focus = () => {
this.ele.focus
? this.ele.focus()
: (ReactDOM.findDOMNode(this.ele) as HTMLInputElement).focus();
if (this.ele.focus) {
this.ele.focus();
} else {
(ReactDOM.findDOMNode(this.ele) as HTMLInputElement).focus();
}
};
blur = () => {
this.ele.blur ? this.ele.blur() : (ReactDOM.findDOMNode(this.ele) as HTMLInputElement).blur();
if (this.ele.blur) {
this.ele.blur();
} else {
(ReactDOM.findDOMNode(this.ele) as HTMLInputElement).blur();
}
};
saveRef = (ele: HTMLInputElement) => {

View File

@ -51,6 +51,7 @@ function isSelectOptionOrSelectOptGroup(child: any): Boolean {
export default class AutoComplete extends React.Component<AutoCompleteProps, {}> {
static Option = Option as React.ClassicComponentClass<OptionProps>;
static OptGroup = OptGroup as React.ClassicComponentClass<OptGroupProps>;
static defaultProps = {
@ -63,6 +64,10 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
private select: any;
saveSelect = (node: any) => {
this.select = node;
};
getInputElement = () => {
const { children } = this.props;
const element =
@ -85,10 +90,6 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
this.select.blur();
}
saveSelect = (node: any) => {
this.select = node;
};
renderAutoComplete = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import Icon from '../icon';
import classNames from 'classnames';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface AvatarProps {
@ -23,7 +23,7 @@ export interface AvatarProps {
children?: React.ReactNode;
alt?: string;
/* callback when img load error */
/* return false to prevent Avatar show default fallback behavior, then you can do fallback by your self*/
/* return false to prevent Avatar show default fallback behavior, then you can do fallback by your self */
onError?: () => boolean;
}
@ -44,8 +44,11 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
};
private avatarNode: HTMLElement;
private avatarChildren: HTMLElement;
private lastChildrenWidth: number;
private lastNodeWidth: number;
componentDidMount() {
@ -127,7 +130,7 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
}
: {};
let children = this.props.children;
let { children } = this.props;
if (src && isImgExist) {
children = <img src={src} srcSet={srcSet} onError={this.handleImgLoadError} alt={alt} />;
} else if (icon) {

View File

@ -12,9 +12,8 @@ const easeInOutCubic = (t: number, b: number, c: number, d: number) => {
t /= d / 2;
if (t < 1) {
return (cc / 2) * t * t * t + b;
} else {
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
}
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
};
function noop() {}
@ -47,6 +46,29 @@ export default class BackTop extends React.Component<BackTopProps, any> {
};
}
componentDidMount() {
const getTarget = this.props.target || getDefaultTarget;
this.scrollEvent = addEventListener(getTarget(), 'scroll', this.handleScroll);
this.handleScroll();
}
componentWillUnmount() {
if (this.scrollEvent) {
this.scrollEvent.remove();
}
}
setScrollTop(value: number) {
const getTarget = this.props.target || getDefaultTarget;
const targetNode = getTarget();
if (targetNode === window) {
document.body.scrollTop = value;
document.documentElement!.scrollTop = value;
} else {
(targetNode as HTMLElement).scrollTop = value;
}
}
getCurrentScrollTop = () => {
const getTarget = this.props.target || getDefaultTarget;
const targetNode = getTarget();
@ -73,17 +95,6 @@ export default class BackTop extends React.Component<BackTopProps, any> {
(this.props.onClick || noop)(e);
};
setScrollTop(value: number) {
const getTarget = this.props.target || getDefaultTarget;
const targetNode = getTarget();
if (targetNode === window) {
document.body.scrollTop = value;
document.documentElement!.scrollTop = value;
} else {
(targetNode as HTMLElement).scrollTop = value;
}
}
handleScroll = () => {
const { visibilityHeight, target = getDefaultTarget } = this.props;
const scrollTop = getScroll(target(), true);
@ -92,18 +103,6 @@ export default class BackTop extends React.Component<BackTopProps, any> {
});
};
componentDidMount() {
const getTarget = this.props.target || getDefaultTarget;
this.scrollEvent = addEventListener(getTarget(), 'scroll', this.handleScroll);
this.handleScroll();
}
componentWillUnmount() {
if (this.scrollEvent) {
this.scrollEvent.remove();
}
}
renderBackTop = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '', children } = this.props;
const prefixCls = getPrefixCls('back-top', customizePrefixCls);

View File

@ -1,9 +1,8 @@
import * as React from 'react';
import { createElement, Component } from 'react';
import React, { createElement, Component } from 'react';
import omit from 'omit.js';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { polyfill } from 'react-lifecycles-compat';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
function getNumberArray(num: string | number | undefined | null) {
return num
@ -18,6 +17,20 @@ function getNumberArray(num: string | number | undefined | null) {
: [];
}
function renderNumberList(position: number) {
const childrenToReturn: React.ReactElement<any>[] = [];
for (let i = 0; i < 30; i++) {
const currentClassName = position === i ? 'current' : '';
childrenToReturn.push(
<p key={i.toString()} className={currentClassName}>
{i % 10}
</p>,
);
}
return childrenToReturn;
}
export interface ScrollNumberProps {
prefixCls?: string;
className?: string;
@ -62,6 +75,21 @@ class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
};
}
componentDidUpdate(_: any, prevState: ScrollNumberState) {
this.lastCount = prevState.count;
const { animateStarted } = this.state;
if (animateStarted) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState(
(__, props) => ({
animateStarted: false,
count: props.count,
}),
this.onAnimated,
);
}
}
getPositionByNum(num: number, i: number) {
const { count } = this.state;
const currentCount = Math.abs(Number(count));
@ -86,20 +114,6 @@ class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
return num;
}
componentDidUpdate(_: any, prevState: ScrollNumberState) {
this.lastCount = prevState.count;
const { animateStarted } = this.state;
if (animateStarted) {
this.setState(
(__, props) => ({
animateStarted: false,
count: props.count,
}),
this.onAnimated,
);
}
}
onAnimated = () => {
const { onAnimated } = this.props;
if (onAnimated) {
@ -107,20 +121,6 @@ class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
}
};
renderNumberList(position: number) {
const childrenToReturn: React.ReactElement<any>[] = [];
for (let i = 0; i < 30; i++) {
const currentClassName = position === i ? 'current' : '';
childrenToReturn.push(
<p key={i.toString()} className={currentClassName}>
{i % 10}
</p>,
);
}
return childrenToReturn;
}
renderCurrentNumber(prefixCls: string, num: number | string, i: number) {
if (typeof num === 'number') {
const position = this.getPositionByNum(num, i);
@ -138,7 +138,7 @@ class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
},
key: i,
},
this.renderNumberList(position),
renderNumberList(position),
);
}

View File

@ -1,6 +1,7 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import Animate from 'rc-animate';
import omit from 'omit.js';
import classNames from 'classnames';
import ScrollNumber from './ScrollNumber';
import { PresetColorTypes } from '../_util/colors';
@ -46,39 +47,6 @@ export default class Badge extends React.Component<BadgeProps, any> {
overflowCount: PropTypes.number,
};
getBadgeClassName(prefixCls: string) {
const { className, children } = this.props;
return classNames(className, prefixCls, {
[`${prefixCls}-status`]: this.hasStatus(),
[`${prefixCls}-not-a-wrapper`]: !children,
}) as string;
}
hasStatus(): boolean {
const { status, color } = this.props;
return !!status || !!color;
}
isZero() {
const numberedDispayCount = this.getNumberedDispayCount();
return numberedDispayCount === '0' || numberedDispayCount === 0;
}
isDot() {
const { dot } = this.props;
const isZero = this.isZero();
return (dot && !isZero) || this.hasStatus();
}
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 { count, overflowCount } = this.props;
const displayCount =
@ -114,6 +82,39 @@ export default class Badge extends React.Component<BadgeProps, any> {
: style;
}
getBadgeClassName(prefixCls: string) {
const { className, children } = this.props;
return classNames(className, prefixCls, {
[`${prefixCls}-status`]: this.hasStatus(),
[`${prefixCls}-not-a-wrapper`]: !children,
}) as string;
}
hasStatus(): boolean {
const { status, color } = this.props;
return !!status || !!color;
}
isZero() {
const numberedDispayCount = this.getNumberedDispayCount();
return numberedDispayCount === '0' || numberedDispayCount === 0;
}
isDot() {
const { dot } = this.props;
const isZero = this.isZero();
return (dot && !isZero) || this.hasStatus();
}
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;
}
renderStatusText(prefixCls: string) {
const { text } = this.props;
const hidden = this.isHidden();
@ -165,22 +166,24 @@ export default class Badge extends React.Component<BadgeProps, any> {
renderBadge = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
count,
showZero,
prefixCls: customizePrefixCls,
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
overflowCount,
className,
style,
children,
dot,
status,
text,
offset,
title,
color,
...restProps
} = this.props;
const omitArr = [
'count',
'showZero',
'overflowCount',
'className',
'style',
'dot',
'offset',
'title',
];
const prefixCls = getPrefixCls('badge', customizePrefixCls);
const scrollNumberPrefixCls = getPrefixCls('scroll-number', customizeScrollNumberPrefixCls);
@ -203,7 +206,11 @@ export default class Badge extends React.Component<BadgeProps, any> {
const styleWithOffset = this.getStyleWithOffset();
const statusTextColor = styleWithOffset && styleWithOffset.color;
return (
<span {...restProps} className={this.getBadgeClassName(prefixCls)} style={styleWithOffset}>
<span
{...omit(restProps, omitArr)}
className={this.getBadgeClassName(prefixCls)}
style={styleWithOffset}
>
<span className={statusCls} style={statusStyle} />
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
{text}
@ -213,7 +220,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
}
return (
<span {...restProps} className={this.getBadgeClassName(prefixCls)}>
<span {...omit(restProps, omitArr)} className={this.getBadgeClassName(prefixCls)}>
{children}
<Animate
component=""

View File

@ -1,8 +1,8 @@
import * as React from 'react';
import React, { cloneElement } from 'react';
import * as PropTypes from 'prop-types';
import { cloneElement } from 'react';
import classNames from 'classnames';
import BreadcrumbItem from './BreadcrumbItem';
import BreadcrumbSeparator from './BreadcrumbSeparator';
import Menu from '../menu';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
@ -50,6 +50,8 @@ function defaultItemRender(route: Route, params: any, routes: Route[], paths: st
export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
static Item: typeof BreadcrumbItem;
static Separator: typeof BreadcrumbSeparator;
static defaultProps = {
separator: '/',
};
@ -58,7 +60,6 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
prefixCls: PropTypes.string,
separator: PropTypes.node,
routes: PropTypes.array,
params: PropTypes.object,
};
getPath = (path: string, params: any) => {
@ -112,6 +113,7 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
);
});
};
renderBreadcrumb = ({ getPrefixCls }: ConfigConsumerProps) => {
let crumbs;
const {
@ -131,11 +133,14 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
if (!element) {
return element;
}
warning(
element.type && element.type.__ANT_BREADCRUMB_ITEM,
element.type &&
(element.type.__ANT_BREADCRUMB_ITEM || element.type.__ANT_BREADCRUMB_SEPARATOR),
'Breadcrumb',
"Only accepts Breadcrumb.Item as it's children",
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
);
return cloneElement(element, {
separator,
key: index,

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import omit from 'omit.js';
import DropDown, { DropDownProps } from '../dropdown/dropdown';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
@ -26,24 +27,18 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
};
renderBreadcrumbItem = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
separator,
children,
overlay,
...restProps
} = this.props;
const { prefixCls: customizePrefixCls, separator, children, ...restProps } = this.props;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
let link;
if ('href' in this.props) {
link = (
<a className={`${prefixCls}-link`} {...restProps}>
<a className={`${prefixCls}-link`} {...omit(restProps, ['overlay'])}>
{children}
</a>
);
} else {
link = (
<span className={`${prefixCls}-link`} {...restProps}>
<span className={`${prefixCls}-link`} {...omit(restProps, ['overlay'])}>
{children}
</span>
);
@ -55,7 +50,9 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
return (
<span>
{link}
<span className={`${prefixCls}-separator`}>{separator}</span>
{separator && separator !== '' && (
<span className={`${prefixCls}-separator`}>{separator}</span>
)}
</span>
);
}
@ -80,6 +77,7 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
}
return breadcrumbItem;
};
render() {
return <ConfigConsumer>{this.renderBreadcrumbItem}</ConfigConsumer>;
}

View File

@ -0,0 +1,17 @@
import * as React from 'react';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export default class BreadcrumbSeparator extends React.Component<any> {
static __ANT_BREADCRUMB_SEPARATOR = true;
renderSeparator = ({ getPrefixCls }: ConfigConsumerProps) => {
const { children } = this.props;
const prefixCls = getPrefixCls('breadcrumb');
return <span className={`${prefixCls}-separator`}>{children || '/'}</span>;
};
render() {
return <ConfigConsumer>{this.renderSeparator}</ConfigConsumer>;
}
}

View File

@ -14,7 +14,7 @@ describe('Breadcrumb', () => {
});
// https://github.com/airbnb/enzyme/issues/875
it('warns on non-Breadcrumb.Item children', () => {
it('warns on non-Breadcrumb.Item and non-Breadcrumb.Separator children', () => {
const MyCom = () => <div>foo</div>;
mount(
<Breadcrumb>
@ -23,7 +23,7 @@ describe('Breadcrumb', () => {
);
expect(errorSpy.mock.calls).toHaveLength(1);
expect(errorSpy.mock.calls[0][0]).toMatch(
"Warning: [antd: Breadcrumb] Only accepts Breadcrumb.Item as it's children",
"Warning: [antd: Breadcrumb] Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
);
});

View File

@ -149,99 +149,6 @@ exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
</div>
`;
exports[`renders ./components/breadcrumb/demo/router.md correctly 1`] = `
<div
class="demo"
>
<div
class="demo-nav"
>
<a
href="#/"
>
Home
</a>
<a
href="#/apps"
>
Application List
</a>
</div>
Home Page
<div
class="ant-alert ant-alert-info ant-alert-no-icon"
data-show="true"
style="margin:16px 0;"
>
<span
class="ant-alert-message"
>
Click the navigation above to switch:
</span>
<span
class="ant-alert-description"
/>
</div>
<div
class="ant-breadcrumb"
>
<span>
<span
class="ant-breadcrumb-link"
>
<span>
Home
</span>
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</span>
</div>
</div>
`;
exports[`renders ./components/breadcrumb/demo/router-4.md correctly 1`] = `
<div
class="demo"
>
<div
class="demo-nav"
>
<a
href="#/"
>
Home
</a>
<a
href="#/apps"
>
Application List
</a>
</div>
Home Page
<div
class="ant-alert ant-alert-info ant-alert-no-icon"
data-show="true"
style="margin:16px 0;"
>
<span
class="ant-alert-message"
>
Click the navigation above to switch:
</span>
<span
class="ant-alert-description"
/>
</div>
<div
class="ant-breadcrumb"
/>
</div>
`;
exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
<div
class="ant-breadcrumb"
@ -299,6 +206,58 @@ exports[`renders ./components/breadcrumb/demo/separator.md correctly 1`] = `
</div>
`;
exports[`renders ./components/breadcrumb/demo/separator-indepent.md correctly 1`] = `
<div
class="ant-breadcrumb"
>
<span>
<span
class="ant-breadcrumb-link"
>
Location
</span>
</span>
<span
class="ant-breadcrumb-separator"
>
:
</span>
<span>
<a
class="ant-breadcrumb-link"
href=""
>
Application Center
</a>
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<a
class="ant-breadcrumb-link"
href=""
>
Application List
</a>
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<span
class="ant-breadcrumb-link"
>
An Application
</span>
</span>
</div>
`;
exports[`renders ./components/breadcrumb/demo/withIcon.md correctly 1`] = `
<div
class="ant-breadcrumb"

View File

@ -0,0 +1,31 @@
---
order: 6
title:
zh-CN: 分隔符
en-US: Configuring the Separator
---
## zh-CN
使用 `Breadcrumb.Separator` 可以自定义分隔符。
## en-US
The separator can be customized by setting the separator property: `Breadcrumb.Separator`
```jsx
import { Breadcrumb } from 'antd';
ReactDOM.render(
<Breadcrumb separator="">
<Breadcrumb.Item>Location</Breadcrumb.Item>
<Breadcrumb.Separator>:</Breadcrumb.Separator>
<Breadcrumb.Item href="">Application Center</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item href="">Application List</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>An Application</Breadcrumb.Item>
</Breadcrumb>,
mountNode,
);
```

View File

@ -1,8 +1,10 @@
import Breadcrumb from './Breadcrumb';
import BreadcrumbItem from './BreadcrumbItem';
import BreadcrumbSeparator from './BreadcrumbSeparator';
export { BreadcrumbProps } from './Breadcrumb';
export { BreadcrumbItemProps } from './BreadcrumbItem';
Breadcrumb.Item = BreadcrumbItem;
Breadcrumb.Separator = BreadcrumbSeparator;
export default Breadcrumb;

View File

@ -32,6 +32,14 @@ title: Breadcrumb
| overlay | 下拉菜单的内容 | [Menu](/components/menu) \| () => Menu | - | 3.17.0 |
| onClick | 单击事件 | (e:MouseEvent)=>void | - | 3.17.0 |
### Breadcrumb.Separator `3.21.0`
| 参数 | 参数 | 类型 | 默认值 | 版本 |
| -------- | -------------- | ----------------- | ------ | ------ |
| children | 要显示的分隔符 | string\|ReactNode | '/' | 3.21.0 |
> 注意:在使用 `Breadcrumb.Separator` 时,其父组件的分隔符必须设置为 `separator=""`,否则会出现父组件默认的分隔符。
### routes
```ts

View File

@ -25,6 +25,7 @@ const ButtonGroup: React.SFC<ButtonGroupProps> = props => (
break;
case 'small':
sizeCls = 'sm';
break;
default:
break;
}

View File

@ -1,9 +1,10 @@
/* eslint-disable react/button-has-type */
import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { polyfill } from 'react-lifecycles-compat';
import Group from './button-group';
import omit from 'omit.js';
import Group from './button-group';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Wave from '../_util/wave';
@ -15,29 +16,6 @@ function isString(str: any) {
return typeof str === 'string';
}
function spaceChildren(children: React.ReactNode, needInserted: boolean) {
let isPrevChildPure: boolean = false;
const childList: React.ReactNode[] = [];
React.Children.forEach(children, child => {
const type = typeof child;
const isCurrentChildPure = type === 'string' || type === 'number';
if (isPrevChildPure && isCurrentChildPure) {
const lastIndex = childList.length - 1;
const lastChild = childList[lastIndex];
childList[lastIndex] = `${lastChild}${child}`;
} else {
childList.push(child);
}
isPrevChildPure = isCurrentChildPure;
});
// Pass to React.Children.map to auto fill key
return React.Children.map(childList, child =>
insertSpace(child as React.ReactChild, needInserted),
);
}
// Insert one space between two chinese characters automatically.
function insertSpace(child: React.ReactChild, needInserted: boolean) {
// Check the child if is undefined or null.
@ -63,6 +41,29 @@ function insertSpace(child: React.ReactChild, needInserted: boolean) {
return child;
}
function spaceChildren(children: React.ReactNode, needInserted: boolean) {
let isPrevChildPure: boolean = false;
const childList: React.ReactNode[] = [];
React.Children.forEach(children, child => {
const type = typeof child;
const isCurrentChildPure = type === 'string' || type === 'number';
if (isPrevChildPure && isCurrentChildPure) {
const lastIndex = childList.length - 1;
const lastChild = childList[lastIndex];
childList[lastIndex] = `${lastChild}${child}`;
} else {
childList.push(child);
}
isPrevChildPure = isCurrentChildPure;
});
// Pass to React.Children.map to auto fill key
return React.Children.map(childList, child =>
insertSpace(child as React.ReactChild, needInserted),
);
}
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'danger', 'link');
export type ButtonType = (typeof ButtonTypes)[number];
const ButtonShapes = tuple('circle', 'circle-outline', 'round');
@ -110,6 +111,7 @@ interface ButtonState {
class Button extends React.Component<ButtonProps, ButtonState> {
static Group: typeof Group;
static __ANT_BUTTON = true;
static defaultProps = {
@ -142,6 +144,7 @@ class Button extends React.Component<ButtonProps, ButtonState> {
}
private delayTimeout: number;
private buttonNode: HTMLElement | null;
constructor(props: ButtonProps) {
@ -166,9 +169,8 @@ class Button extends React.Component<ButtonProps, ButtonState> {
const { loading } = this.props;
if (loading && typeof loading !== 'boolean' && loading.delay) {
this.delayTimeout = window.setTimeout(() => this.setState({ loading }), loading.delay);
} else if (prevProps.loading === this.props.loading) {
return;
} else {
} else if (prevProps.loading !== this.props.loading) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ loading });
}
}
@ -183,6 +185,17 @@ class Button extends React.Component<ButtonProps, ButtonState> {
this.buttonNode = node;
};
handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
const { loading } = this.state;
const { onClick } = this.props;
if (loading) {
return;
}
if (onClick) {
(onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)(e);
}
};
fixTwoCNChar() {
// Fix for HOC usage like <FormatMessage />
if (!this.buttonNode) {
@ -202,17 +215,6 @@ class Button extends React.Component<ButtonProps, ButtonState> {
}
}
handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
const { loading } = this.state;
const { onClick } = this.props;
if (!!loading) {
return;
}
if (onClick) {
(onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)(e);
}
};
isNeedInserted() {
const { icon, children } = this.props;
return React.Children.count(children) === 1 && !icon;
@ -228,7 +230,6 @@ class Button extends React.Component<ButtonProps, ButtonState> {
children,
icon,
ghost,
loading: _loadingProp,
block,
...rest
} = this.props;
@ -289,7 +290,7 @@ class Button extends React.Component<ButtonProps, ButtonState> {
const buttonNode = (
<button
{...(otherProps as NativeButtonProps)}
{...(omit(otherProps, ['loading']) as NativeButtonProps)}
type={htmlType}
className={classes}
onClick={this.handleClick}

View File

@ -3,8 +3,20 @@ import * as moment from 'moment';
import Select from '../select';
import { Group, Button, RadioChangeEvent } from '../radio';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
const { Option } = Select;
function getMonthsLocale(value: moment.Moment) {
const current = value.clone();
const localeData = value.localeData();
const months: any[] = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
return months;
}
export interface RenderHeader {
value: moment.Moment;
onChange?: (value: moment.Moment) => void;
@ -63,17 +75,6 @@ export default class Header extends React.Component<HeaderProps, any> {
);
}
getMonthsLocale(value: moment.Moment) {
const current = value.clone();
const localeData = value.localeData();
const months: any[] = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
return months;
}
getMonthSelectElement(prefixCls: string, month: number, months: number[]) {
const { fullscreen, validRange, value } = this.props;
const options: React.ReactElement<any>[] = [];
@ -124,7 +125,7 @@ export default class Header extends React.Component<HeaderProps, any> {
}
}
const onValueChange = this.props.onValueChange;
const { onValueChange } = this.props;
if (onValueChange) {
onValueChange(newValue);
}
@ -133,7 +134,7 @@ export default class Header extends React.Component<HeaderProps, any> {
onMonthChange = (month: string) => {
const newValue = this.props.value.clone();
newValue.month(parseInt(month, 10));
const onValueChange = this.props.onValueChange;
const { onValueChange } = this.props;
if (onValueChange) {
onValueChange(newValue);
}
@ -144,7 +145,7 @@ export default class Header extends React.Component<HeaderProps, any> {
};
onTypeChange = (type: string) => {
const onTypeChange = this.props.onTypeChange;
const { onTypeChange } = this.props;
if (onTypeChange) {
onTypeChange(type);
}
@ -161,7 +162,7 @@ export default class Header extends React.Component<HeaderProps, any> {
const yearReactNode = this.getYearSelectElement(prefixCls, value.year());
const monthReactNode =
type === 'month'
? this.getMonthSelectElement(prefixCls, value.month(), this.getMonthsLocale(value))
? this.getMonthSelectElement(prefixCls, value.month(), getMonthsLocale(value))
: null;
return {
yearReactNode,

View File

@ -2,12 +2,12 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import * as moment from 'moment';
import FullCalendar from 'rc-calendar/lib/FullCalendar';
import { polyfill } from 'react-lifecycles-compat';
import Header, { HeaderRender } from './Header';
import enUS from './locale/en_US';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import interopDefault from '../_util/interopDefault';
import { polyfill } from 'react-lifecycles-compat';
export { HeaderProps } from './Header';
@ -104,47 +104,6 @@ class Calendar extends React.Component<CalendarProps, CalendarState> {
};
}
monthCellRender = (value: moment.Moment) => {
const { monthCellRender = noop as Function } = this.props;
const { prefixCls } = this;
return (
<div className={`${prefixCls}-month`}>
<div className={`${prefixCls}-value`}>{value.localeData().monthsShort(value)}</div>
<div className={`${prefixCls}-content`}>{monthCellRender(value)}</div>
</div>
);
};
dateCellRender = (value: moment.Moment) => {
const { dateCellRender = noop as Function } = this.props;
const { prefixCls } = this;
return (
<div className={`${prefixCls}-date`}>
<div className={`${prefixCls}-value`}>{zerofixed(value.date())}</div>
<div className={`${prefixCls}-content`}>{dateCellRender(value)}</div>
</div>
);
};
setValue = (value: moment.Moment, way: 'select' | 'changePanel') => {
const prevValue = this.props.value || this.state.value;
const { mode } = this.state;
if (!('value' in this.props)) {
this.setState({ value });
}
if (way === 'select') {
if (prevValue && prevValue.month() !== value.month()) {
this.onPanelChange(value, mode);
}
if (this.props.onSelect) {
this.props.onSelect(value);
}
} else if (way === 'changePanel') {
this.onPanelChange(value, mode);
}
};
onHeaderValueChange = (value: moment.Moment) => {
this.setValue(value, 'changePanel');
};
@ -168,6 +127,25 @@ class Calendar extends React.Component<CalendarProps, CalendarState> {
this.setValue(value, 'select');
};
setValue = (value: moment.Moment, way: 'select' | 'changePanel') => {
const prevValue = this.props.value || this.state.value;
const { mode } = this.state;
if (!('value' in this.props)) {
this.setState({ value });
}
if (way === 'select') {
if (prevValue && prevValue.month() !== value.month()) {
this.onPanelChange(value, mode);
}
if (this.props.onSelect) {
this.props.onSelect(value);
}
} else if (way === 'changePanel') {
this.onPanelChange(value, mode);
}
};
getDateRange = (
validRange: [moment.Moment, moment.Moment],
disabledDate?: (current: moment.Moment) => boolean,
@ -195,6 +173,28 @@ class Calendar extends React.Component<CalendarProps, CalendarState> {
return result;
};
monthCellRender = (value: moment.Moment) => {
const { monthCellRender = noop as Function } = this.props;
const { prefixCls } = this;
return (
<div className={`${prefixCls}-month`}>
<div className={`${prefixCls}-value`}>{value.localeData().monthsShort(value)}</div>
<div className={`${prefixCls}-content`}>{monthCellRender(value)}</div>
</div>
);
};
dateCellRender = (value: moment.Moment) => {
const { dateCellRender = noop as Function } = this.props;
const { prefixCls } = this;
return (
<div className={`${prefixCls}-date`}>
<div className={`${prefixCls}-value`}>{zerofixed(value.date())}</div>
<div className={`${prefixCls}-content`}>{dateCellRender(value)}</div>
</div>
);
};
renderCalendar = (locale: any, localeCode: string) => {
const { state, props } = this;
const { value, mode } = state;
@ -213,7 +213,7 @@ class Calendar extends React.Component<CalendarProps, CalendarState> {
const monthCellRender = monthFullCellRender || this.monthCellRender;
const dateCellRender = dateFullCellRender || this.dateCellRender;
let disabledDate = props.disabledDate;
let { disabledDate } = props;
if (props.validRange) {
disabledDate = this.getDateRange(props.validRange, disabledDate);

View File

@ -0,0 +1,2 @@
import ms_MY from '../../date-picker/locale/ms_MY';
export default ms_MY;

View File

@ -0,0 +1,2 @@
import ta_IN from '../../date-picker/locale/ta_IN';
export default ta_IN;

View File

@ -46,7 +46,11 @@ class App extends React.Component {
<Card
style={{ width: 300, marginTop: 16 }}
actions={[<Icon type="setting" />, <Icon type="edit" />, <Icon type="ellipsis" />]}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,
<Icon type="ellipsis" key="ellipsis" />,
]}
>
<Skeleton loading={loading} avatar active>
<Meta

View File

@ -27,7 +27,11 @@ ReactDOM.render(
src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png"
/>
}
actions={[<Icon type="setting" />, <Icon type="edit" />, <Icon type="ellipsis" />]}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,
<Icon type="ellipsis" key="ellipsis" />,
]}
>
<Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}

View File

@ -10,6 +10,16 @@ import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import { Omit } from '../_util/type';
function getAction(actions: React.ReactNode[]) {
const actionList = actions.map((action, index) => (
// eslint-disable-next-line react/no-array-index-key
<li style={{ width: `${100 / actions.length}%` }} key={`action-${index}`}>
<span>{action}</span>
</li>
));
return actionList;
}
export { CardGridProps } from './Grid';
export { CardMetaProps } from './Meta';
@ -48,6 +58,7 @@ export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 't
export default class Card extends React.Component<CardProps, {}> {
static Grid: typeof Grid = Grid;
static Meta: typeof Meta = Meta;
componentDidMount() {
@ -65,6 +76,15 @@ export default class Card extends React.Component<CardProps, {}> {
}
}
// For 2.x compatible
getCompatibleHoverable() {
const { noHovering, hoverable } = this.props;
if ('noHovering' in this.props) {
return !noHovering || hoverable;
}
return !!hoverable;
}
onTabChange = (key: string) => {
if (this.props.onTabChange) {
this.props.onTabChange(key);
@ -81,24 +101,6 @@ export default class Card extends React.Component<CardProps, {}> {
return containGrid;
}
getAction(actions: React.ReactNode[]) {
const actionList = actions.map((action, index) => (
<li style={{ width: `${100 / actions.length}%` }} key={`action-${index}`}>
<span>{action}</span>
</li>
));
return actionList;
}
// For 2.x compatible
getCompatibleHoverable() {
const { noHovering, hoverable } = this.props;
if ('noHovering' in this.props) {
return !noHovering || hoverable;
}
return !!hoverable;
}
renderCard = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
@ -106,8 +108,6 @@ export default class Card extends React.Component<CardProps, {}> {
extra,
headStyle = {},
bodyStyle = {},
noHovering,
hoverable,
title,
loading,
bordered = true,
@ -221,9 +221,9 @@ export default class Card extends React.Component<CardProps, {}> {
);
const actionDom =
actions && actions.length ? (
<ul className={`${prefixCls}-actions`}>{this.getAction(actions)}</ul>
<ul className={`${prefixCls}-actions`}>{getAction(actions)}</ul>
) : null;
const divProps = omit(others, ['onTabChange']);
const divProps = omit(others, ['onTabChange', 'noHovering', 'hoverable']);
return (
<div {...divProps} className={classString}>
{head}

View File

@ -1,7 +1,7 @@
import * as React from 'react';
import debounce from 'lodash/debounce';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { Settings } from 'react-slick';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
// matchMedia polyfill for
@ -85,6 +85,20 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
}
}
getDotPosition(): DotPosition {
if (this.props.dotPosition) {
return this.props.dotPosition;
}
if ('vertical' in this.props) {
return this.props.vertical ? 'right' : 'bottom';
}
return 'bottom';
}
saveSlick = (node: any) => {
this.slick = node;
};
onWindowResized = () => {
// Fix https://github.com/ant-design/ant-design/issues/2550
const { autoplay } = this.props;
@ -93,10 +107,6 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
}
};
saveSlick = (node: any) => {
this.slick = node;
};
next() {
this.slick.slickNext();
}
@ -109,15 +119,6 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
this.slick.slickGoTo(slide, dontAnimate);
}
getDotPosition(): DotPosition {
if (this.props.dotPosition) {
return this.props.dotPosition;
} else if ('vertical' in this.props) {
return this.props.vertical ? 'right' : 'bottom';
}
return 'bottom';
}
renderCarousel = ({ getPrefixCls }: ConfigConsumerProps) => {
const props = {
...this.props,

View File

@ -1216,9 +1216,9 @@ exports[`Cascader should render not found content 1`] = `
role="menuitem"
title=""
>
<OriginEmpty
<Empty
className="ant-empty-small"
image="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
image={<Simple />}
>
<LocaleReceiver
componentName="Empty"
@ -1229,10 +1229,40 @@ exports[`Cascader should render not found content 1`] = `
<div
className="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<Simple>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fillRule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fillRule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</Simple>
</div>
<p
className="ant-empty-description"
@ -1241,7 +1271,7 @@ exports[`Cascader should render not found content 1`] = `
</p>
</div>
</LocaleReceiver>
</OriginEmpty>
</Empty>
</li>
</ul>
</div>
@ -1509,9 +1539,9 @@ exports[`Cascader should show not found content when options.length is 0 1`] = `
role="menuitem"
title=""
>
<OriginEmpty
<Empty
className="ant-empty-small"
image="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
image={<Simple />}
>
<LocaleReceiver
componentName="Empty"
@ -1522,10 +1552,40 @@ exports[`Cascader should show not found content when options.length is 0 1`] = `
<div
className="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<Simple>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fillRule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fillRule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</Simple>
</div>
<p
className="ant-empty-description"
@ -1534,7 +1594,7 @@ exports[`Cascader should show not found content when options.length is 0 1`] = `
</p>
</div>
</LocaleReceiver>
</OriginEmpty>
</Empty>
</li>
</ul>
</div>

View File

@ -72,13 +72,13 @@ export interface CascaderProps {
popupClassName?: string;
/** 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` */
popupPlacement?: string;
/** 输入框占位文本*/
/** 输入框占位文本 */
placeholder?: string;
/** 输入框大小,可选 `large` `default` `small` */
size?: string;
/** 禁用*/
/** 禁用 */
disabled?: boolean;
/** 是否支持清除*/
/** 是否支持清除 */
allowClear?: boolean;
showSearch?: boolean | ShowSearchType;
notFoundContent?: React.ReactNode;
@ -262,6 +262,34 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
};
}
setValue = (value: string[], selectedOptions: CascaderOptionType[] = []) => {
if (!('value' in this.props)) {
this.setState({ value });
}
const { onChange } = this.props;
if (onChange) {
onChange(value, selectedOptions);
}
};
getLabel() {
const { options, displayRender = defaultDisplayRender as Function } = this.props;
const names = getFilledFieldNames(this.props);
const { value } = this.state;
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
const selectedOptions: CascaderOptionType[] = arrayTreeFilter(
options,
(o: CascaderOptionType, level: number) => o[names.value] === unwrappedValue[level],
{ childrenKeyName: names.children },
);
const label = selectedOptions.map(o => o[names.label]);
return displayRender(label, selectedOptions);
}
saveInput = (node: Input) => {
this.input = node;
};
handleChange = (value: any, selectedOptions: CascaderOptionType[]) => {
this.setState({ inputValue: '' });
if (selectedOptions[0].__IS_FILTERED_OPTION) {
@ -282,7 +310,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
}));
}
const onPopupVisibleChange = this.props.onPopupVisibleChange;
const { onPopupVisibleChange } = this.props;
if (onPopupVisibleChange) {
onPopupVisibleChange(popupVisible);
}
@ -317,30 +345,6 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
this.setState({ inputValue });
};
setValue = (value: string[], selectedOptions: CascaderOptionType[] = []) => {
if (!('value' in this.props)) {
this.setState({ value });
}
const onChange = this.props.onChange;
if (onChange) {
onChange(value, selectedOptions);
}
};
getLabel() {
const { options, displayRender = defaultDisplayRender as Function } = this.props;
const names = getFilledFieldNames(this.props);
const value = this.state.value;
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
const selectedOptions: CascaderOptionType[] = arrayTreeFilter(
options,
(o: CascaderOptionType, level: number) => o[names.value] === unwrappedValue[level],
{ childrenKeyName: names.children },
);
const label = selectedOptions.map(o => o[names.label]);
return displayRender(label, selectedOptions);
}
clearSelection = (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.stopPropagation();
@ -417,10 +421,6 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
this.input.blur();
}
saveInput = (node: Input) => {
this.input = node;
};
renderCascader = (
{ getPopupContainer: getContextPopupContainer, getPrefixCls, renderEmpty }: ConfigConsumerProps,
locale: CascaderLocale,
@ -495,7 +495,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
'filedNames', // For old compatibility
]);
let options = props.options;
let { options } = props;
if (options.length > 0) {
if (state.inputValue) {
options = this.generateFilteredOptions(prefixCls, renderEmpty);
@ -524,8 +524,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
dropdownMenuColumnStyle.height = 'auto'; // Height of one row.
}
// The default value of `matchInputWidth` is `true`
const resultListMatchInputWidth =
(showSearch as ShowSearchType).matchInputWidth === false ? false : true;
const resultListMatchInputWidth = (showSearch as ShowSearchType).matchInputWidth !== false;
if (resultListMatchInputWidth && (state.inputValue || isNotFound) && this.input) {
dropdownMenuColumnStyle.width = this.input.input.offsetWidth;
}

View File

@ -45,6 +45,7 @@ export interface CheckboxChangeEvent {
class Checkbox extends React.Component<CheckboxProps, {}> {
static Group: typeof CheckboxGroup;
static defaultProps = {
indeterminate: false,
};
@ -65,6 +66,18 @@ class Checkbox extends React.Component<CheckboxProps, {}> {
}
}
shouldComponentUpdate(
nextProps: CheckboxProps,
nextState: {},
nextContext: CheckboxGroupContext,
) {
return (
!shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState) ||
!shallowEqual(this.context.checkboxGroup, nextContext.checkboxGroup)
);
}
componentDidUpdate({ value: prevValue }: CheckboxProps) {
const { value } = this.props;
const { checkboxGroup = {} } = this.context || {};
@ -82,17 +95,9 @@ class Checkbox extends React.Component<CheckboxProps, {}> {
}
}
shouldComponentUpdate(
nextProps: CheckboxProps,
nextState: {},
nextContext: CheckboxGroupContext,
) {
return (
!shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState) ||
!shallowEqual(this.context.checkboxGroup, nextContext.checkboxGroup)
);
}
saveCheckbox = (node: any) => {
this.rcCheckbox = node;
};
focus() {
this.rcCheckbox.focus();
@ -102,10 +107,6 @@ class Checkbox extends React.Component<CheckboxProps, {}> {
this.rcCheckbox.blur();
}
saveCheckbox = (node: any) => {
this.rcCheckbox = node;
};
renderCheckbox = ({ getPrefixCls }: ConfigConsumerProps) => {
const { props, context } = this;
const {
@ -141,6 +142,7 @@ class Checkbox extends React.Component<CheckboxProps, {}> {
[`${prefixCls}-indeterminate`]: indeterminate,
});
return (
// eslint-disable-next-line jsx-a11y/label-has-associated-control
<label
className={classString}
style={style}

View File

@ -96,18 +96,6 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
}
registerValue = (value: string) => {
this.setState(({ registeredValues }) => ({
registeredValues: [...registeredValues, value],
}));
};
cancelValue = (value: string) => {
this.setState(({ registeredValues }) => ({
registeredValues: registeredValues.filter(val => val !== value),
}));
};
getOptions() {
const { options } = this.props;
// https://github.com/Microsoft/TypeScript/issues/7960
@ -122,6 +110,18 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
});
}
cancelValue = (value: string) => {
this.setState(({ registeredValues }) => ({
registeredValues: registeredValues.filter(val => val !== value),
}));
};
registerValue = (value: string) => {
this.setState(({ registeredValues }) => ({
registeredValues: [...registeredValues, value],
}));
};
toggleOption = (option: CheckboxOptionType) => {
const { registeredValues } = this.state;
const optionIndex = this.state.value.indexOf(option.value);
@ -134,7 +134,7 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
if (!('value' in this.props)) {
this.setState({ value });
}
const onChange = this.props.onChange;
const { onChange } = this.props;
if (onChange) {
const options = this.getOptions();
onChange(
@ -157,7 +157,7 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
const domProps = omit(restProps, ['children', 'defaultValue', 'value', 'onChange', 'disabled']);
let children = props.children;
let { children } = props;
if (options && options.length > 0) {
children = this.getOptions().map(option => (
<Checkbox

View File

@ -31,7 +31,7 @@
border-radius: @border-radius-sm;
visibility: hidden;
animation: antCheckboxEffect 0.36s ease-in-out;
animation-fill-mode: both;
animation-fill-mode: backwards;
content: '';
}

View File

@ -222,6 +222,7 @@ exports[`renders ./components/comment/demo/list.md correctly 1`] = `
class="ant-comment-avatar"
>
<img
alt="comment-avatar"
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</div>
@ -275,6 +276,7 @@ exports[`renders ./components/comment/demo/list.md correctly 1`] = `
class="ant-comment-avatar"
>
<img
alt="comment-avatar"
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</div>

View File

@ -44,7 +44,7 @@ class App extends React.Component {
const { likes, dislikes, action } = this.state;
const actions = [
<span>
<span key="comment-basic-like">
<Tooltip title="Like">
<Icon
type="like"
@ -54,7 +54,7 @@ class App extends React.Component {
</Tooltip>
<span style={{ paddingLeft: 8, cursor: 'auto' }}>{likes}</span>
</span>,
<span>
<span key=' key="comment-basic-dislike"'>
<Tooltip title="Dislike">
<Icon
type="dislike"
@ -64,7 +64,7 @@ class App extends React.Component {
</Tooltip>
<span style={{ paddingLeft: 8, cursor: 'auto' }}>{dislikes}</span>
</span>,
<span>Reply to</span>,
<span key="comment-basic-reply-to">Reply to</span>,
];
return (

View File

@ -19,7 +19,7 @@ import moment from 'moment';
const data = [
{
actions: [<span>Reply to</span>],
actions: [<span key="comment-list-reply-to-0">Reply to</span>],
author: 'Han Solo',
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
content: (
@ -44,7 +44,7 @@ const data = [
),
},
{
actions: [<span>Reply to</span>],
actions: [<span key="comment-list-reply-to-0">Reply to</span>],
author: 'Han Solo',
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
content: (

View File

@ -18,7 +18,7 @@ import { Comment, Avatar } from 'antd';
const ExampleComment = ({ children }) => (
<Comment
actions={[<span>Reply to</span>]}
actions={[<span key="comment-nested-reply-to">Reply to</span>]}
author={<a>Han Solo</a>}
avatar={
<Avatar

View File

@ -2,6 +2,15 @@ import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
function getAction(actions: React.ReactNode[]) {
if (!actions || !actions.length) {
return null;
}
// eslint-disable-next-line react/no-array-index-key
const actionList = actions.map((action, index) => <li key={`action-${index}`}>{action}</li>);
return actionList;
}
export interface CommentProps {
/** List of action items rendered below the comment content */
actions?: Array<React.ReactNode>;
@ -24,14 +33,6 @@ export interface CommentProps {
}
export default class Comment extends React.Component<CommentProps, {}> {
getAction(actions: React.ReactNode[]) {
if (!actions || !actions.length) {
return null;
}
const actionList = actions.map((action, index) => <li key={`action-${index}`}>{action}</li>);
return actionList;
}
renderNested = (prefixCls: string, children: any) => {
return <div className={classNames(`${prefixCls}-nested`)}>{children}</div>;
};
@ -54,13 +55,13 @@ export default class Comment extends React.Component<CommentProps, {}> {
const avatarDom = (
<div className={`${prefixCls}-avatar`}>
{typeof avatar === 'string' ? <img src={avatar} /> : avatar}
{typeof avatar === 'string' ? <img src={avatar} alt="comment-avatar" /> : avatar}
</div>
);
const actionDom =
actions && actions.length ? (
<ul className={`${prefixCls}-actions`}>{this.getAction(actions)}</ul>
<ul className={`${prefixCls}-actions`}>{getAction(actions)}</ul>
) : null;
const authorContent = (

View File

@ -11671,10 +11671,38 @@ exports[`ConfigProvider components Table configProvider 1`] = `
<div
class="config-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="config-empty-description"
@ -11889,10 +11917,38 @@ exports[`ConfigProvider components Table normal 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -12107,10 +12163,38 @@ exports[`ConfigProvider components Table prefixCls 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -16032,10 +16116,38 @@ exports[`ConfigProvider components Transfer configProvider 1`] = `
<div
class="config-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="config-empty-description"
@ -16144,10 +16256,38 @@ exports[`ConfigProvider components Transfer configProvider 1`] = `
<div
class="config-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="config-empty-description"
@ -16209,10 +16349,38 @@ exports[`ConfigProvider components Transfer normal 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -16321,10 +16489,38 @@ exports[`ConfigProvider components Transfer normal 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -16386,10 +16582,38 @@ exports[`ConfigProvider components Transfer prefixCls 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -16498,10 +16722,38 @@ exports[`ConfigProvider components Transfer prefixCls 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"

View File

@ -0,0 +1,61 @@
import React from 'react';
import { mount } from 'enzyme';
import ConfigProvider from '..';
import LocaleProvider from '../../locale-provider';
import locale from '../../locale/zh_CN';
import TimePicker from '../../time-picker';
describe('ConfigProvider.Locale', () => {
it('not throw', () => {
if (process.env.REACT === '15') {
return;
}
mount(
<ConfigProvider locale={{}}>
<span />
<span />
</ConfigProvider>,
);
});
describe('support legacy LocaleProvider', () => {
function testLocale(wrapper) {
expect(wrapper.find('input').props().placeholder).toBe(locale.TimePicker.placeholder);
}
it('LocaleProvider', () => {
const wrapper = mount(
<LocaleProvider locale={locale}>
<TimePicker />
</LocaleProvider>,
);
testLocale(wrapper);
});
it('LocaleProvider > ConfigProvider', () => {
const wrapper = mount(
<LocaleProvider locale={locale}>
<ConfigProvider>
<TimePicker />
</ConfigProvider>
</LocaleProvider>,
);
testLocale(wrapper);
});
it('ConfigProvider > ConfigProvider', () => {
const wrapper = mount(
<ConfigProvider locale={locale}>
<ConfigProvider>
<TimePicker />
</ConfigProvider>
</ConfigProvider>,
);
testLocale(wrapper);
});
});
});

View File

@ -0,0 +1,187 @@
---
order: 1
title:
zh-CN: 国际化
en-US: Locale
---
## zh-CN
此处列出 Ant Design 中需要国际化支持的组件,你可以在演示里切换语言。
## en-US
Components which need localization support are listed here, you can toggle the language in the demo.
```jsx
import {
ConfigProvider,
Pagination,
DatePicker,
TimePicker,
Calendar,
Popconfirm,
Table,
Modal,
Button,
Select,
Transfer,
Radio,
} from 'antd';
import zhCN from 'antd/es/locale/zh_CN';
import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('en');
const { Option } = Select;
const { RangePicker } = DatePicker;
const columns = [
{
title: 'Name',
dataIndex: 'name',
filters: [
{
text: 'filter1',
value: 'filter1',
},
],
},
{
title: 'Age',
dataIndex: 'age',
},
];
class Page extends React.Component {
state = {
visible: false,
};
showModal = () => {
this.setState({ visible: true });
};
hideModal = () => {
this.setState({ visible: false });
};
render() {
const info = () => {
Modal.info({
title: 'some info',
content: 'some info',
});
};
const confirm = () => {
Modal.confirm({
title: 'some info',
content: 'some info',
});
};
return (
<div className="locale-components">
<div className="example">
<Pagination defaultCurrent={1} total={50} showSizeChanger />
</div>
<div className="example">
<Select showSearch style={{ width: 200 }}>
<Option value="jack">jack</Option>
<Option value="lucy">lucy</Option>
</Select>
<DatePicker />
<TimePicker />
<RangePicker style={{ width: 200 }} />
</div>
<div className="example">
<Button type="primary" onClick={this.showModal}>
Show Modal
</Button>
<Button onClick={info}>Show info</Button>
<Button onClick={confirm}>Show confirm</Button>
<Popconfirm title="Question?">
<a href="#">Click to confirm</a>
</Popconfirm>
</div>
<div className="example">
<Transfer dataSource={[]} showSearch targetKeys={[]} render={item => item.title} />
</div>
<div style={{ width: 319, border: '1px solid #d9d9d9', borderRadius: 4 }}>
<Calendar fullscreen={false} value={moment()} />
</div>
<div className="example">
<Table dataSource={[]} columns={columns} />
</div>
<Modal title="Locale Modal" visible={this.state.visible} onCancel={this.hideModal}>
<p>Locale Modal</p>
</Modal>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
locale: null,
};
}
changeLocale = e => {
const localeValue = e.target.value;
this.setState({ locale: localeValue });
if (!localeValue) {
moment.locale('en');
} else {
moment.locale('zh-cn');
}
};
render() {
const { locale } = this.state;
return (
<div>
<div className="change-locale">
<span style={{ marginRight: 16 }}>Change locale of components: </span>
<Radio.Group defaultValue={undefined} onChange={this.changeLocale}>
<Radio.Button key="en" value={undefined}>
English
</Radio.Button>
<Radio.Button key="cn" value={zhCN}>
中文
</Radio.Button>
</Radio.Group>
</div>
<ConfigProvider locale={locale}>
<Page
key={locale ? locale.locale : 'en' /* Have to refresh for production environment */}
/>
</ConfigProvider>
</div>
);
}
}
ReactDOM.render(<App />, mountNode);
```
```css
.locale-components {
border-top: 1px solid #d9d9d9;
padding-top: 16px;
}
.example {
margin: 16px 0;
}
.example > * {
margin-right: 8px;
}
.change-locale {
margin-bottom: 16px;
}
```

View File

@ -42,4 +42,5 @@ Some component use dynamic style to support wave effect. You can config `csp` pr
| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validateMessages) } | - | 4.0 |
| renderEmpty | set empty content of components. Ref [Empty](/components/empty/) | Function(componentName: string): ReactNode | - | 3.12.2 |
| getPopupContainer | to set the container of the popup element. The default is to create a `div` element in `body`. | Function(triggerNode) | `() => document.body` | 3.11.0 |
| locale | language package setting, you can find the packages in [antd/es/locale](http://unpkg.com/antd/es/locale/) | object | 3.21.0 |
| prefixCls | set prefix class | string | ant | 3.12.0 |

View File

@ -1,7 +1,12 @@
// TODO: remove this lint
// SFC has specified a displayName, but not worked.
/* eslint-disable react/display-name */
import * as React from 'react';
import { FormProvider as RcFormProvider } from 'rc-field-form';
import { ValidateMessages } from 'rc-field-form/lib/interface';
import defaultRenderEmpty, { RenderEmptyHandler } from './renderEmpty';
import LocaleProvider, { Locale, ANT_MARK } from '../locale-provider';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
export { RenderEmptyHandler };
@ -16,6 +21,7 @@ export interface ConfigConsumerProps {
renderEmpty: RenderEmptyHandler;
csp?: CSPConfig;
autoInsertSpaceInButton?: boolean;
locale?: Locale;
}
export const configConsumerProps = [
@ -25,6 +31,7 @@ export const configConsumerProps = [
'renderEmpty',
'csp',
'autoInsertSpaceInButton',
'locale',
];
export interface ConfigProviderProps {
@ -37,6 +44,7 @@ export interface ConfigProviderProps {
form?: {
validateMessages?: ValidateMessages;
};
locale?: Locale;
}
export const ConfigContext = React.createContext<ConfigConsumerProps>({
@ -61,7 +69,7 @@ class ConfigProvider extends React.Component<ConfigProviderProps> {
return suffixCls ? `${prefixCls}-${suffixCls}` : prefixCls;
};
renderProvider = (context: ConfigConsumerProps) => {
renderProvider = (context: ConfigConsumerProps, legacyLocale: Locale) => {
const {
children,
getPopupContainer,
@ -69,6 +77,7 @@ class ConfigProvider extends React.Component<ConfigProviderProps> {
csp,
autoInsertSpaceInButton,
form,
locale,
} = this.props;
const config: ConfigConsumerProps = {
@ -94,11 +103,25 @@ class ConfigProvider extends React.Component<ConfigProviderProps> {
);
}
return <ConfigContext.Provider value={config}>{childNode}</ConfigContext.Provider>;
return (
<ConfigContext.Provider value={config}>
<LocaleProvider locale={locale || legacyLocale} _ANT_MARK__={ANT_MARK}>
{childNode}
</LocaleProvider>
</ConfigContext.Provider>
);
};
render() {
return <ConfigConsumer>{this.renderProvider}</ConfigConsumer>;
return (
<LocaleReceiver>
{(_, __, legacyLocale) => (
<ConfigConsumer>
{context => this.renderProvider(context, legacyLocale as Locale)}
</ConfigConsumer>
)}
</LocaleReceiver>
);
}
}

View File

@ -43,4 +43,5 @@ return (
| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form/#validateMessages) } | - | 4.0 |
| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty/) | Function(componentName: string): ReactNode | - | 3.12.2 |
| getPopupContainer | 弹出框Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | Function(triggerNode) | () => document.body | 3.11.0 |
| locale | 语言包配置,语言包可到 [antd/es/locale](http://unpkg.com/antd/es/locale/) 目录下寻找 | object | - | 3.21.0 |
| prefixCls | 设置统一样式前缀 | string | ant | 3.12.0 |

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import Icon from '../icon';
import classNames from 'classnames';
import Icon from '../icon';
export default function InputIcon(props: { suffixIcon: React.ReactNode; prefixCls: string }) {
const { suffixIcon, prefixCls } = props;

View File

@ -30,10 +30,9 @@ function getShowDateFromValue(value: RangePickerValue, mode?: string | string[])
}
if (mode && mode[0] === 'month') {
return [start, end] as RangePickerValue;
} else {
const newEnd = end && end.isSame(start, 'month') ? end.clone().add(1, 'month') : end;
return [start, newEnd] as RangePickerValue;
}
const newEnd = end && end.isSame(start, 'month') ? end.clone().add(1, 'month') : end;
return [start, newEnd] as RangePickerValue;
}
function pickerValueAdapter(
@ -102,7 +101,9 @@ class RangePicker extends React.Component<any, RangePickerState> {
}
private picker: HTMLSpanElement;
private prefixCls?: string;
private tagPrefixCls?: string;
constructor(props: any) {
@ -133,6 +134,17 @@ class RangePicker extends React.Component<any, RangePickerState> {
}
}
setValue(value: RangePickerValue, hidePanel?: boolean) {
this.handleChange(value);
if ((hidePanel || !this.props.showTime) && !('open' in this.props)) {
this.setState({ open: false });
}
}
savePicker = (node: HTMLSpanElement) => {
this.picker = node;
};
clearSelection = (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.stopPropagation();
@ -143,7 +155,7 @@ class RangePicker extends React.Component<any, RangePickerState> {
clearHoverValue = () => this.setState({ hoverValue: [] });
handleChange = (value: RangePickerValue) => {
const props = this.props;
const { props } = this;
if (!('value' in props)) {
this.setState(({ showDate }) => ({
value,
@ -210,13 +222,6 @@ class RangePicker extends React.Component<any, RangePickerState> {
}
};
setValue(value: RangePickerValue, hidePanel?: boolean) {
this.handleChange(value);
if ((hidePanel || !this.props.showTime) && !('open' in this.props)) {
this.setState({ open: false });
}
}
focus() {
this.picker.focus();
}
@ -225,10 +230,6 @@ class RangePicker extends React.Component<any, RangePickerState> {
this.picker.blur();
}
savePicker = (node: HTMLSpanElement) => {
this.picker = node;
};
renderFooter = () => {
const { ranges, renderExtraFooter } = this.props;
const { prefixCls, tagPrefixCls } = this;

View File

@ -39,6 +39,7 @@ class WeekPicker extends React.Component<any, WeekPickerState> {
}
private input: any;
private prefixCls?: string;
constructor(props: any) {
@ -62,6 +63,10 @@ class WeekPicker extends React.Component<any, WeekPickerState> {
}
}
saveInput = (node: any) => {
this.input = node;
};
weekDateRender = (current: any) => {
const selectedValue = this.state.value;
const { prefixCls } = this;
@ -105,13 +110,6 @@ class WeekPicker extends React.Component<any, WeekPickerState> {
this.handleChange(null);
};
renderFooter = (...args: any[]) => {
const { prefixCls, renderExtraFooter } = this.props;
return renderExtraFooter ? (
<div className={`${prefixCls}-footer-extra`}>{renderExtraFooter(...args)}</div>
) : null;
};
focus() {
this.input.focus();
}
@ -120,8 +118,11 @@ class WeekPicker extends React.Component<any, WeekPickerState> {
this.input.blur();
}
saveInput = (node: any) => {
this.input = node;
renderFooter = (...args: any[]) => {
const { prefixCls, renderExtraFooter } = this.props;
return renderExtraFooter ? (
<div className={`${prefixCls}-footer-extra`}>{renderExtraFooter(...args)}</div>
) : null;
};
renderWeekPicker = ({ getPrefixCls }: ConfigConsumerProps) => {

View File

@ -78,12 +78,8 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
}
}
renderFooter = (...args: any[]) => {
const { renderExtraFooter } = this.props;
const { prefixCls } = this;
return renderExtraFooter ? (
<div className={`${prefixCls}-footer-extra`}>{renderExtraFooter(...args)}</div>
) : null;
saveInput = (node: any) => {
this.input = node;
};
clearSelection = (e: React.MouseEvent<HTMLElement>) => {
@ -126,8 +122,12 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
this.input.blur();
}
saveInput = (node: any) => {
this.input = node;
renderFooter = (...args: any[]) => {
const { renderExtraFooter } = this.props;
const { prefixCls } = this;
return renderExtraFooter ? (
<div className={`${prefixCls}-footer-extra`}>{renderExtraFooter(...args)}</div>
) : null;
};
renderPicker = ({ getPrefixCls }: ConfigConsumerProps) => {
@ -272,5 +272,6 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
}
}
polyfill(CalenderWrapper);
return CalenderWrapper;
}

View File

@ -21,12 +21,12 @@ There are four kinds of picker:
### Localization
The default locale is en-US, if you need to use other languages, recommend to use internationalized components provided by us at the entrance. Look at: [LocaleProvider](http://ant.design/components/locale-provider/).
The default locale is en-US, if you need to use other languages, recommend to use internationalized components provided by us at the entrance. Look at: [ConfigProvider](http://ant.design/components/config-provider/).
If there are special needs (only modifying single component language), Please use the property: local. Example: [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json).
```jsx
import locale from 'antd/lib/date-picker/locale/zh_CN';
import locale from 'antd/es/date-picker/locale/zh_CN';
<DatePicker locale={locale} />;
```

View File

@ -22,12 +22,12 @@ subtitle: 日期选择框
### 国际化配置
默认配置为 en-US如果你需要设置其他语言推荐在入口处使用我们提供的国际化组件详见[LocaleProvider 国际化](http://ant.design/components/locale-provider-cn/)。
默认配置为 en-US如果你需要设置其他语言推荐在入口处使用我们提供的国际化组件详见[ConfigProvider 国际化](http://ant.design/components/config-provider-cn/)。
如有特殊需求(仅修改单一组件的语言),请使用 locale 参数,参考:[默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json)。
```jsx
import locale from 'antd/lib/date-picker/locale/zh_CN';
import locale from 'antd/es/date-picker/locale/zh_CN';
<DatePicker locale={locale} />;
```

View File

@ -0,0 +1,19 @@
import CalendarLocale from 'rc-calendar/lib/locale/ms_MY';
import TimePickerLocale from '../../time-picker/locale/ms_MY';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Pilih tarikh',
rangePlaceholder: ['Tarikh mula', 'Tarikh 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;

View File

@ -0,0 +1,20 @@
// Tamil Locale added to rc-calendar
import CalendarLocale from 'rc-calendar/lib/locale/ta_IN';
import TimePickerLocale from '../../time-picker/locale/ta_IN';
// 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;

View File

@ -277,9 +277,12 @@
&-last-month-cell &-date,
&-next-month-btn-day &-date {
color: @disabled-color !important;
background: transparent !important;
border-color: transparent !important;
&,
&:hover {
color: @disabled-color;
background: transparent;
border-color: transparent;
}
}
&-disabled-cell &-date {

View File

@ -84,7 +84,10 @@
transform: translateX(-50%);
}
.@{calendar-prefix-cls}-today {
.@{calendar-prefix-cls}-today
:not(.@{calendar-prefix-cls}-disabled-cell)
:not(.@{calendar-prefix-cls}-last-month-cell)
:not(.@{calendar-prefix-cls}-next-month-btn-day) {
.@{calendar-prefix-cls}-date {
color: @primary-color;
background: @primary-2;

View File

@ -89,6 +89,22 @@ export default function wrapPicker(Picker: React.ComponentClass<any>, pickerType
}
}
savePicker = (node: any) => {
this.picker = node;
};
getDefaultLocale = () => {
const result = {
...enUS,
...this.props.locale,
};
result.lang = {
...result.lang,
...(this.props.locale || {}).lang,
};
return result;
};
handleOpenChange = (open: boolean) => {
const { onOpenChange } = this.props;
onOpenChange(open);
@ -130,22 +146,6 @@ export default function wrapPicker(Picker: React.ComponentClass<any>, pickerType
this.picker.blur();
}
savePicker = (node: any) => {
this.picker = node;
};
getDefaultLocale = () => {
const result = {
...enUS,
...this.props.locale,
};
result.lang = {
...result.lang,
...(this.props.locale || {}).lang,
};
return result;
};
renderPicker = (locale: any, localeCode: string) => {
const { format, showTime } = this.props;
const mergedPickerType = showTime ? `${pickerType}Time` : pickerType;

View File

@ -0,0 +1,72 @@
import * as React from 'react';
import classNames from 'classnames';
import { DescriptionsItemProps } from './index';
interface ColProps {
child: React.ReactElement<DescriptionsItemProps>;
bordered: boolean;
colon: boolean;
type?: 'label' | 'content';
layout?: 'horizontal' | 'vertical';
}
const Col: React.SFC<ColProps> = props => {
const { child, bordered, colon, type, layout } = props;
const { prefixCls, label, className, children, span = 1 } = child.props;
const labelProps: any = {
className: classNames(`${prefixCls}-item-label`, className, {
[`${prefixCls}-item-colon`]: colon,
[`${prefixCls}-item-no-label`]: !label,
}),
key: 'label',
};
if (layout === 'vertical') {
labelProps.colSpan = span * 2 - 1;
}
if (bordered) {
if (type === 'label') {
return <th {...labelProps}>{label}</th>;
}
return (
<td
className={classNames(`${prefixCls}-item-content`, className)}
key="content"
colSpan={span * 2 - 1}
>
{children}
</td>
);
}
if (layout === 'vertical') {
if (type === 'content') {
return (
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
<span className={`${prefixCls}-item-content`} key="content">
{children}
</span>
</td>
);
}
return (
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
<span
className={classNames(`${prefixCls}-item-label`, { [`${prefixCls}-item-colon`]: colon })}
key="label"
>
{label}
</span>
</td>
);
}
return (
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
<span {...labelProps}>{label}</span>
<span className={`${prefixCls}-item-content`} key="content">
{children}
</span>
</td>
);
};
export default Col;

View File

@ -22,7 +22,7 @@ exports[`renders ./components/descriptions/demo/basic.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
UserName
</span>
@ -37,7 +37,7 @@ exports[`renders ./components/descriptions/demo/basic.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Telephone
</span>
@ -52,7 +52,7 @@ exports[`renders ./components/descriptions/demo/basic.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Live
</span>
@ -71,7 +71,7 @@ exports[`renders ./components/descriptions/demo/basic.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Remark
</span>
@ -86,7 +86,7 @@ exports[`renders ./components/descriptions/demo/basic.md correctly 1`] = `
colspan="2"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Address
</span>
@ -121,7 +121,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Product
</th>
@ -132,7 +132,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
Cloud Database
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Billing Mode
</th>
@ -143,7 +143,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
Prepaid
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Automatic Renewal
</th>
@ -158,7 +158,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Order time
</th>
@ -169,7 +169,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
2018-04-24 18:00:00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Usage Time
</th>
@ -184,7 +184,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Status
</th>
@ -210,7 +210,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Negotiated Amount
</th>
@ -221,7 +221,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
$80.00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Discount
</th>
@ -232,7 +232,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
$20.00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Official Receipts
</th>
@ -247,7 +247,7 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Config Info
</th>
@ -294,7 +294,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Product
</th>
@ -305,7 +305,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
Cloud Database
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Billing
</th>
@ -316,7 +316,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
Prepaid
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
time
</th>
@ -331,7 +331,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Amount
</th>
@ -342,7 +342,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
$80.00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Discount
</th>
@ -353,7 +353,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
$20.00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Official
</th>
@ -368,7 +368,7 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Config Info
</th>
@ -479,7 +479,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Product
</th>
@ -490,7 +490,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
Cloud Database
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Billing
</th>
@ -501,7 +501,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
Prepaid
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
time
</th>
@ -516,7 +516,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Amount
</th>
@ -527,7 +527,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
$80.00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Discount
</th>
@ -538,7 +538,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
$20.00
</td>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Official
</th>
@ -553,7 +553,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
class="ant-descriptions-row"
>
<th
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Config Info
</th>
@ -604,7 +604,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
UserName
</span>
@ -614,7 +614,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Telephone
</span>
@ -624,7 +624,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Live
</span>
@ -672,7 +672,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
colspan="1"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Remark
</span>
@ -682,7 +682,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
colspan="2"
>
<span
class="ant-descriptions-item-label"
class="ant-descriptions-item-label ant-descriptions-item-colon"
>
Address
</span>
@ -735,24 +735,24 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
<tr
class="ant-descriptions-row"
>
<td
class="ant-descriptions-item-label"
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Product
</td>
<td
class="ant-descriptions-item-label"
</th>
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Billing Mode
</td>
<td
class="ant-descriptions-item-label"
</th>
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Automatic Renewal
</td>
</th>
</tr>
<tr
class="ant-descriptions-row"
@ -779,18 +779,18 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
<tr
class="ant-descriptions-row"
>
<td
class="ant-descriptions-item-label"
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Order time
</td>
<td
class="ant-descriptions-item-label"
</th>
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="5"
>
Usage Time
</td>
</th>
</tr>
<tr
class="ant-descriptions-row"
@ -811,12 +811,12 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
<tr
class="ant-descriptions-row"
>
<td
class="ant-descriptions-item-label"
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="5"
>
Status
</td>
</th>
</tr>
<tr
class="ant-descriptions-row"
@ -842,24 +842,24 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
<tr
class="ant-descriptions-row"
>
<td
class="ant-descriptions-item-label"
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Negotiated Amount
</td>
<td
class="ant-descriptions-item-label"
</th>
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Discount
</td>
<td
class="ant-descriptions-item-label"
</th>
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="1"
>
Official Receipts
</td>
</th>
</tr>
<tr
class="ant-descriptions-row"
@ -886,12 +886,12 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
<tr
class="ant-descriptions-row"
>
<td
class="ant-descriptions-item-label"
<th
class="ant-descriptions-item-label ant-descriptions-item-colon"
colspan="5"
>
Config Info
</td>
</th>
</tr>
<tr
class="ant-descriptions-row"

View File

@ -1,5 +1,74 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Descriptions Descriptions support colon 1`] = `
<Descriptions
colon={false}
column={
Object {
"lg": 3,
"md": 3,
"sm": 2,
"xl": 3,
"xs": 1,
"xxl": 3,
}
}
size="default"
>
<div
className="ant-descriptions"
>
<div
className="ant-descriptions-view"
>
<table>
<tbody>
<tr
className="ant-descriptions-row"
key="0"
>
<Col
bordered={false}
child={
<DescriptionsItem
label="Product"
prefixCls="ant-descriptions"
span={1}
>
Cloud Database
</DescriptionsItem>
}
colon={false}
key="label-0"
layout="horizontal"
type="label"
>
<td
className="ant-descriptions-item"
colSpan={1}
>
<span
className="ant-descriptions-item-label"
key="label"
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</Col>
</tr>
</tbody>
</table>
</div>
</div>
</Descriptions>
`;
exports[`Descriptions Descriptions support style 1`] = `
<Descriptions
column={
@ -36,21 +105,37 @@ exports[`Descriptions Descriptions support style 1`] = `
className="ant-descriptions-row"
key="0"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
prefixCls="ant-descriptions"
span={1}
>
Cloud Database
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label ant-descriptions-item-no-label"
key="label"
/>
<span
className="ant-descriptions-item-content"
key="content"
<td
className="ant-descriptions-item"
colSpan={1}
>
Cloud Database
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon ant-descriptions-item-no-label"
key="label"
/>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</Col>
</tr>
</tbody>
</table>
@ -85,23 +170,41 @@ exports[`Descriptions Descriptions.Item support className 1`] = `
className="ant-descriptions-row"
key="0"
>
<td
className="ant-descriptions-item my-class"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
className="my-class"
label="Product"
prefixCls="ant-descriptions"
span={1}
>
Cloud Database
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item my-class"
colSpan={1}
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
<span
className="ant-descriptions-item-label my-class ant-descriptions-item-colon"
key="label"
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</Col>
</tr>
</tbody>
</table>
@ -127,81 +230,144 @@ exports[`Descriptions column is number 1`] = `
className="ant-descriptions-row"
key="0"
>
<td
className="ant-descriptions-item"
colSpan={1}
key=".$.0"
<Col
bordered={false}
child={
<DescriptionsItem
label="Product"
prefixCls="ant-descriptions"
>
Cloud Database
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
<td
className="ant-descriptions-item"
colSpan={1}
key=".$.1"
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</Col>
<Col
bordered={false}
child={
<DescriptionsItem
label="Billing"
prefixCls="ant-descriptions"
>
Prepaid
</DescriptionsItem>
}
colon={true}
key="label-1"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Billing
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Prepaid
</span>
</td>
<td
className="ant-descriptions-item"
colSpan={1}
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Billing
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Prepaid
</span>
</td>
</Col>
<Col
bordered={false}
child={
<DescriptionsItem
label="time"
prefixCls="ant-descriptions"
>
18:00:00
</DescriptionsItem>
}
colon={true}
key="label-2"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
time
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
18:00:00
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
time
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
18:00:00
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="1"
>
<td
className="ant-descriptions-item"
colSpan={3}
<Col
bordered={false}
child={
<DescriptionsItem
label="Amount"
prefixCls="ant-descriptions"
span={3}
>
$80.00
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={3}
>
Amount
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
$80.00
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Amount
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
$80.00
</span>
</td>
</Col>
</tr>
</tbody>
</table>
@ -237,129 +403,259 @@ exports[`Descriptions vertical layout 1`] = `
className="ant-descriptions-row"
key="label-0"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Product"
prefixCls="ant-descriptions"
>
Cloud Database
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="vertical"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Product
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Product
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="content-0"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Product"
prefixCls="ant-descriptions"
>
Cloud Database
</DescriptionsItem>
}
colon={true}
key="content-0"
layout="vertical"
type="content"
>
<span
className="ant-descriptions-item-content"
key="content"
<td
className="ant-descriptions-item"
colSpan={1}
>
Cloud Database
</span>
</td>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="label-1"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Billing"
prefixCls="ant-descriptions"
>
Prepaid
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="vertical"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Billing
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Billing
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="content-1"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Billing"
prefixCls="ant-descriptions"
>
Prepaid
</DescriptionsItem>
}
colon={true}
key="content-0"
layout="vertical"
type="content"
>
<span
className="ant-descriptions-item-content"
key="content"
<td
className="ant-descriptions-item"
colSpan={1}
>
Prepaid
</span>
</td>
<span
className="ant-descriptions-item-content"
key="content"
>
Prepaid
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="label-2"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="time"
prefixCls="ant-descriptions"
>
18:00:00
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="vertical"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
time
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
time
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="content-2"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="time"
prefixCls="ant-descriptions"
>
18:00:00
</DescriptionsItem>
}
colon={true}
key="content-0"
layout="vertical"
type="content"
>
<span
className="ant-descriptions-item-content"
key="content"
<td
className="ant-descriptions-item"
colSpan={1}
>
18:00:00
</span>
</td>
<span
className="ant-descriptions-item-content"
key="content"
>
18:00:00
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="label-3"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Amount"
prefixCls="ant-descriptions"
span={1}
>
$80.00
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="vertical"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Amount
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Amount
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="content-3"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Amount"
prefixCls="ant-descriptions"
span={1}
>
$80.00
</DescriptionsItem>
}
colon={true}
key="content-0"
layout="vertical"
type="content"
>
<span
className="ant-descriptions-item-content"
key="content"
<td
className="ant-descriptions-item"
colSpan={1}
>
$80.00
</span>
</td>
<span
className="ant-descriptions-item-content"
key="content"
>
$80.00
</span>
</td>
</Col>
</tr>
</tbody>
</table>
@ -394,89 +690,154 @@ exports[`Descriptions when item is rendered conditionally 1`] = `
className="ant-descriptions-row"
key="0"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Product"
prefixCls="ant-descriptions"
>
Cloud Database
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="1"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Billing"
prefixCls="ant-descriptions"
>
Prepaid
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Billing
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Prepaid
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Billing
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Prepaid
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="2"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="time"
prefixCls="ant-descriptions"
>
18:00:00
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
time
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
18:00:00
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
time
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
18:00:00
</span>
</td>
</Col>
</tr>
<tr
className="ant-descriptions-row"
key="3"
>
<td
className="ant-descriptions-item"
colSpan={1}
<Col
bordered={false}
child={
<DescriptionsItem
label="Amount"
prefixCls="ant-descriptions"
span={1}
>
$80.00
</DescriptionsItem>
}
colon={true}
key="label-0"
layout="horizontal"
type="label"
>
<span
className="ant-descriptions-item-label"
key="label"
<td
className="ant-descriptions-item"
colSpan={1}
>
Amount
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
$80.00
</span>
</td>
<span
className="ant-descriptions-item-label ant-descriptions-item-colon"
key="label"
>
Amount
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
$80.00
</span>
</td>
</Col>
</tr>
</tbody>
</table>

View File

@ -152,6 +152,15 @@ describe('Descriptions', () => {
expect(wrapper).toMatchSnapshot();
});
it('Descriptions support colon', () => {
const wrapper = mount(
<Descriptions colon={false}>
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
</Descriptions>,
);
expect(wrapper).toMatchSnapshot();
});
it('Descriptions support style', () => {
const wrapper = mount(
<Descriptions style={{ backgroundColor: '#e8e8e8' }}>

View File

@ -22,6 +22,7 @@ Commonly displayed on the details page.
| column | the number of `DescriptionItems` in a row,could be a number or a object like `{ xs: 8, sm: 16, md: 24}`,(Only set `bordered={true}` to take effect) | number | 3 | 3.19.0 |
| size | set the size of the list. Can be set to `middle`,`small`, or not filled | `default | middle | small` | false | 3.19.0 |
| layout | Define description layout | `horizontal | vertical` | `horizontal` | 3.19.8 |
| colon | change default props `colon` value of `Descriptions.Item` | boolean | true | 3.21.0 |
### DescriptionItem

View File

@ -7,6 +7,7 @@ import ResponsiveObserve, {
responsiveArray,
} from '../_util/responsiveObserve';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Col from './Col';
export interface DescriptionsItemProps {
prefixCls?: string;
@ -29,6 +30,7 @@ export interface DescriptionsProps {
title?: React.ReactNode;
column?: number | Partial<Record<Breakpoint, number>>;
layout?: 'horizontal' | 'vertical';
colon?: boolean;
}
/**
@ -69,96 +71,13 @@ const generateChildrenRows = (
return childrenArray;
};
/**
* This code is for handling react15 does not support returning an array,
* It can convert a children into th and td
* @param child DescriptionsItem
* @returns
* <>
* <th>{DescriptionsItem.label}</th>
* <td>{DescriptionsItem.children}</td>
* </>
*/
const renderCol = (child: React.ReactElement<DescriptionsItemProps>, bordered: boolean) => {
const { prefixCls, label, className, children, span = 1 } = child.props;
if (bordered) {
return [
<th
className={classNames(`${prefixCls}-item-label`, className, {
[`${prefixCls}-item-no-label`]: !label,
})}
key="label"
>
{label}
</th>,
<td
className={classNames(`${prefixCls}-item-content`, className)}
key="content"
colSpan={span * 2 - 1}
>
{children}
</td>,
];
}
return (
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
<span
className={classNames(`${prefixCls}-item-label`, {
[`${prefixCls}-item-no-label`]: !label,
})}
key="label"
>
{label}
</span>
<span className={`${prefixCls}-item-content`} key="content">
{children}
</span>
</td>
);
};
const renderLabelCol = (child: React.ReactElement<DescriptionsItemProps>, bordered: boolean) => {
const { prefixCls, label, span = 1 } = child.props;
if (bordered) {
return (
<td className={`${prefixCls}-item-label`} key="label" colSpan={span * 2 - 1}>
{label}
</td>
);
}
return (
<td colSpan={span} className={`${prefixCls}-item`}>
<span className={`${prefixCls}-item-label`} key="label">
{label}
</span>
</td>
);
};
const renderContentCol = (child: React.ReactElement<DescriptionsItemProps>, bordered: boolean) => {
const { prefixCls, children, span = 1 } = child.props;
if (bordered) {
return (
<td className={`${prefixCls}-item-content`} key="content" colSpan={span * 2 - 1}>
{children}
</td>
);
}
return (
<td colSpan={span} className={`${prefixCls}-item`}>
<span className={`${prefixCls}-item-content`} key="content">
{children}
</span>
</td>
);
};
const renderRow = (
children: React.ReactElement<DescriptionsItemProps>[],
index: number,
{ prefixCls, column, isLast }: { prefixCls: string; column: number; isLast: boolean },
bordered: boolean,
layout: string,
layout: 'horizontal' | 'vertical',
colon: boolean,
) => {
// copy children,prevent changes to incoming parameters
const childrenArray = [...children];
@ -169,41 +88,51 @@ const renderRow = (
span,
});
}
childrenArray.push(lastChildren);
const renderCol = (
childrenItem: React.ReactElement<DescriptionsItemProps>,
type: 'label' | 'content',
idx: number,
) => (
<Col
child={childrenItem}
bordered={bordered}
colon={colon}
type={type}
key={`${type}-${idx}`}
layout={layout}
/>
);
const cloneChildren: JSX.Element[] = [];
const cloneContentChildren: JSX.Element[] = [];
React.Children.forEach(
childrenArray,
(childrenItem: React.ReactElement<DescriptionsItemProps>, idx: number) => {
cloneChildren.push(renderCol(childrenItem, 'label', idx));
if (layout === 'vertical') {
cloneContentChildren.push(renderCol(childrenItem, 'content', idx));
} else if (bordered) {
cloneChildren.push(renderCol(childrenItem, 'content', idx));
}
},
);
if (layout === 'vertical') {
const cloneLabelChildren = React.Children.map(
childrenArray,
(childrenItem: React.ReactElement<DescriptionsItemProps>) => {
return renderLabelCol(childrenItem, bordered);
},
);
const cloneContentChildren = React.Children.map(
childrenArray,
(childrenItem: React.ReactElement<DescriptionsItemProps>) => {
return renderContentCol(childrenItem, bordered);
},
);
return [
<tr className={`${prefixCls}-row`} key={`label-${index}`}>
{cloneLabelChildren}
{renderLabelCol(lastChildren, bordered)}
{cloneChildren}
</tr>,
<tr className={`${prefixCls}-row`} key={`content-${index}`}>
{cloneContentChildren}
{renderContentCol(lastChildren, bordered)}
</tr>,
];
}
const cloneChildren = React.Children.map(
childrenArray,
(childrenItem: React.ReactElement<DescriptionsItemProps>) => {
return renderCol(childrenItem, bordered);
},
);
return (
<tr className={`${prefixCls}-row`} key={index}>
{cloneChildren}
{renderCol(lastChildren, bordered)}
</tr>
);
};
@ -227,13 +156,17 @@ class Descriptions extends React.Component<
size: 'default',
column: defaultColumnMap,
};
static Item: typeof DescriptionsItem = DescriptionsItem;
state: {
screens: BreakpointMap;
} = {
screens: {},
};
token: string;
componentDidMount() {
const { column } = this.props;
this.token = ResponsiveObserve.subscribe(screens => {
@ -260,7 +193,7 @@ class Descriptions extends React.Component<
}
}
}
//If the configuration is not an object, it is a number, return number
// If the configuration is not an object, it is a number, return number
if (typeof column === 'number') {
return column as number;
}
@ -281,6 +214,7 @@ class Descriptions extends React.Component<
children,
bordered = false,
layout = 'horizontal',
colon = true,
style,
} = this.props;
const prefixCls = getPrefixCls('descriptions', customizePrefixCls);
@ -324,6 +258,7 @@ class Descriptions extends React.Component<
},
bordered,
layout,
colon,
),
)}
</tbody>

View File

@ -23,6 +23,7 @@ cols: 1
| column | 一行的 `DescriptionItems` 数量,可以写成像素值或支持响应式的对象写法 `{ xs: 8, sm: 16, md: 24}` | number | 3 | 3.19.0 |
| size | 设置列表的大小。可以设置为 `middle` 、`small`, 或不填(只有设置 `bordered={true}` 生效) | `default | middle | small` | false | 3.19.0 |
| layout | 描述布局 | `horizontal | vertical` | `horizontal` | 3.19.8 |
| colon | 配置 `Descriptions.Item``colon` 的默认值 | boolean | true | 3.21.0 |
### DescriptionItem

View File

@ -47,6 +47,12 @@
position: relative;
top: -0.5px;
margin: 0 8px 0 2px;
content: ' ';
}
}
&-item-colon {
&::after {
content: ':';
}
}

View File

@ -25,7 +25,7 @@ const Divider: React.SFC<DividerProps> = props => (
...restProps
} = props;
const prefixCls = getPrefixCls('divider', customizePrefixCls);
const orientationPrefix = orientation.length > 0 ? '-' + orientation : orientation;
const orientationPrefix = orientation.length > 0 ? `-${orientation}` : orientation;
const classString = classNames(className, prefixCls, `${prefixCls}-${type}`, {
[`${prefixCls}-with-text${orientationPrefix}`]: children,
[`${prefixCls}-dashed`]: !!dashed,

View File

@ -75,7 +75,14 @@ class App extends React.Component {
]}
bordered
renderItem={item => (
<List.Item key={item.id} actions={[<a onClick={this.showDrawer}>View Profile</a>]}>
<List.Item
key={item.id}
actions={[
<a onClick={this.showDrawer} key={`a-${item.id}`}>
View Profile
</a>,
]}
>
<List.Item.Meta
avatar={
<Avatar src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png" />

View File

@ -1,8 +1,9 @@
import * as React from 'react';
import RcDrawer from 'rc-drawer';
import createReactContext from '@ant-design/create-react-context';
import warning from '../_util/warning';
import classNames from 'classnames';
import omit from 'omit.js';
import warning from '../_util/warning';
import Icon from '../icon';
import { withConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { tuple } from '../_util/type';
@ -159,6 +160,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
const { closable, prefixCls, onClose } = this.props;
return (
closable && (
// eslint-disable-next-line react/button-has-type
<button onClick={onClose} aria-label="Close" className={`${prefixCls}-close`}>
<Icon type="close" />
</button>
@ -208,27 +210,12 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
renderProvider = (value: Drawer) => {
const {
prefixCls,
zIndex,
style,
placement,
className,
wrapClassName,
width,
height,
closable,
destroyOnClose,
mask,
bodyStyle,
title,
push,
visible,
// ConfigConsumerProps
getPopupContainer,
rootPrefixCls,
getPrefixCls,
renderEmpty,
csp,
autoInsertSpaceInButton,
...rest
} = this.props;
warning(
@ -248,7 +235,22 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
<DrawerContext.Provider value={this}>
<RcDrawer
handler={false}
{...rest}
{...omit(rest, [
'zIndex',
'style',
'closable',
'destroyOnClose',
'bodyStyle',
'title',
'push',
'visible',
'getPopupContainer',
'rootPrefixCls',
'getPrefixCls',
'renderEmpty',
'csp',
'autoInsertSpaceInButton',
])}
{...offsetStyle}
prefixCls={prefixCls}
open={this.props.visible}

View File

@ -54,6 +54,7 @@ export interface DropDownProps {
export default class Dropdown extends React.Component<DropDownProps, any> {
static Button: typeof DropdownButton;
static defaultProps = {
mouseEnterDelay: 0.15,
mouseLeaveDelay: 0.1,
@ -90,7 +91,7 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
'Dropdown',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
`mode="${overlayProps.mode}" is not supported for Dropdown's Menu.`,
);
// menu cannot be selectable in dropdown defaultly

View File

@ -7,10 +7,65 @@ exports[`renders ./components/empty/demo/basic.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTg0IiBoZWlnaHQ9IjE1MiIgdmlld0JveD0iMCAwIDE4NCAxNTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI0IDMxLjY3KSI+CiAgICAgIDxlbGxpcHNlIGZpbGwtb3BhY2l0eT0iLjgiIGZpbGw9IiNGNUY1RjciIGN4PSI2Ny43OTciIGN5PSIxMDYuODkiIHJ4PSI2Ny43OTciIHJ5PSIxMi42NjgiLz4KICAgICAgPHBhdGggZD0iTTEyMi4wMzQgNjkuNjc0TDk4LjEwOSA0MC4yMjljLTEuMTQ4LTEuMzg2LTIuODI2LTIuMjI1LTQuNTkzLTIuMjI1aC01MS40NGMtMS43NjYgMC0zLjQ0NC44MzktNC41OTIgMi4yMjVMMTMuNTYgNjkuNjc0djE1LjM4M2gxMDguNDc1VjY5LjY3NHoiIGZpbGw9IiNBRUI4QzIiLz4KICAgICAgPHBhdGggZD0iTTEwMS41MzcgODYuMjE0TDgwLjYzIDYxLjEwMmMtMS4wMDEtMS4yMDctMi41MDctMS44NjctNC4wNDgtMS44NjdIMzEuNzI0Yy0xLjU0IDAtMy4wNDcuNjYtNC4wNDggMS44NjdMNi43NjkgODYuMjE0djEzLjc5Mmg5NC43NjhWODYuMjE0eiIgZmlsbD0idXJsKCNsaW5lYXJHcmFkaWVudC0xKSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTMuNTYpIi8+CiAgICAgIDxwYXRoIGQ9Ik0zMy44MyAwaDY3LjkzM2E0IDQgMCAwIDEgNCA0djkzLjM0NGE0IDQgMCAwIDEtNCA0SDMzLjgzYTQgNCAwIDAgMS00LTRWNGE0IDQgMCAwIDEgNC00eiIgZmlsbD0iI0Y1RjVGNyIvPgogICAgICA8cGF0aCBkPSJNNDIuNjc4IDkuOTUzaDUwLjIzN2EyIDIgMCAwIDEgMiAyVjM2LjkxYTIgMiAwIDAgMS0yIDJINDIuNjc4YTIgMiAwIDAgMS0yLTJWMTEuOTUzYTIgMiAwIDAgMSAyLTJ6TTQyLjk0IDQ5Ljc2N2g0OS43MTNhMi4yNjIgMi4yNjIgMCAxIDEgMCA0LjUyNEg0Mi45NGEyLjI2MiAyLjI2MiAwIDAgMSAwLTQuNTI0ek00Mi45NCA2MS41M2g0OS43MTNhMi4yNjIgMi4yNjIgMCAxIDEgMCA0LjUyNUg0Mi45NGEyLjI2MiAyLjI2MiAwIDAgMSAwLTQuNTI1ek0xMjEuODEzIDEwNS4wMzJjLS43NzUgMy4wNzEtMy40OTcgNS4zNi02LjczNSA1LjM2SDIwLjUxNWMtMy4yMzggMC01Ljk2LTIuMjktNi43MzQtNS4zNmE3LjMwOSA3LjMwOSAwIDAgMS0uMjIyLTEuNzlWNjkuNjc1aDI2LjMxOGMyLjkwNyAwIDUuMjUgMi40NDggNS4yNSA1LjQydi4wNGMwIDIuOTcxIDIuMzcgNS4zNyA1LjI3NyA1LjM3aDM0Ljc4NWMyLjkwNyAwIDUuMjc3LTIuNDIxIDUuMjc3LTUuMzkzVjc1LjFjMC0yLjk3MiAyLjM0My01LjQyNiA1LjI1LTUuNDI2aDI2LjMxOHYzMy41NjljMCAuNjE3LS4wNzcgMS4yMTYtLjIyMSAxLjc4OXoiIGZpbGw9IiNEQ0UwRTYiLz4KICAgIDwvZz4KICAgIDxwYXRoIGQ9Ik0xNDkuMTIxIDMzLjI5MmwtNi44MyAyLjY1YTEgMSAwIDAgMS0xLjMxNy0xLjIzbDEuOTM3LTYuMjA3Yy0yLjU4OS0yLjk0NC00LjEwOS02LjUzNC00LjEwOS0xMC40MDhDMTM4LjgwMiA4LjEwMiAxNDguOTIgMCAxNjEuNDAyIDAgMTczLjg4MSAwIDE4NCA4LjEwMiAxODQgMTguMDk3YzAgOS45OTUtMTAuMTE4IDE4LjA5Ny0yMi41OTkgMTguMDk3LTQuNTI4IDAtOC43NDQtMS4wNjYtMTIuMjgtMi45MDJ6IiBmaWxsPSIjRENFMEU2Ii8+CiAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDkuNjUgMTUuMzgzKSIgZmlsbD0iI0ZGRiI+CiAgICAgIDxlbGxpcHNlIGN4PSIyMC42NTQiIGN5PSIzLjE2NyIgcng9IjIuODQ5IiByeT0iMi44MTUiLz4KICAgICAgPHBhdGggZD0iTTUuNjk4IDUuNjNIMEwyLjg5OC43MDR6TTkuMjU5LjcwNGg0Ljk4NVY1LjYzSDkuMjU5eiIvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg=="
/>
<svg
height="152"
viewBox="0 0 184 152"
width="184"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
>
<g
transform="translate(24 31.67)"
>
<ellipse
cx="67.797"
cy="106.89"
fill="#F5F5F7"
fill-opacity=".8"
rx="67.797"
ry="12.668"
/>
<path
d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z"
fill="#AEB8C2"
/>
<path
d="M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z"
fill="url(#linearGradient-1)"
transform="translate(13.56)"
/>
<path
d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"
fill="#F5F5F7"
/>
<path
d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z"
fill="#DCE0E6"
/>
</g>
<path
d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z"
fill="#DCE0E6"
/>
<g
fill="#FFF"
transform="translate(149.65 15.383)"
>
<ellipse
cx="20.654"
cy="3.167"
rx="2.849"
ry="2.815"
/>
<path
d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -222,10 +277,38 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -334,10 +417,38 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -364,6 +475,7 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
>
<div
class="ant-table ant-table-default ant-table-empty ant-table-scroll-position-left"
style="margin-top:8px"
>
<div
class="ant-table-content"
@ -434,10 +546,38 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -472,10 +612,38 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"
@ -538,10 +706,65 @@ exports[`renders ./components/empty/demo/description.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="empty"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTg0IiBoZWlnaHQ9IjE1MiIgdmlld0JveD0iMCAwIDE4NCAxNTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI0IDMxLjY3KSI+CiAgICAgIDxlbGxpcHNlIGZpbGwtb3BhY2l0eT0iLjgiIGZpbGw9IiNGNUY1RjciIGN4PSI2Ny43OTciIGN5PSIxMDYuODkiIHJ4PSI2Ny43OTciIHJ5PSIxMi42NjgiLz4KICAgICAgPHBhdGggZD0iTTEyMi4wMzQgNjkuNjc0TDk4LjEwOSA0MC4yMjljLTEuMTQ4LTEuMzg2LTIuODI2LTIuMjI1LTQuNTkzLTIuMjI1aC01MS40NGMtMS43NjYgMC0zLjQ0NC44MzktNC41OTIgMi4yMjVMMTMuNTYgNjkuNjc0djE1LjM4M2gxMDguNDc1VjY5LjY3NHoiIGZpbGw9IiNBRUI4QzIiLz4KICAgICAgPHBhdGggZD0iTTEwMS41MzcgODYuMjE0TDgwLjYzIDYxLjEwMmMtMS4wMDEtMS4yMDctMi41MDctMS44NjctNC4wNDgtMS44NjdIMzEuNzI0Yy0xLjU0IDAtMy4wNDcuNjYtNC4wNDggMS44NjdMNi43NjkgODYuMjE0djEzLjc5Mmg5NC43NjhWODYuMjE0eiIgZmlsbD0idXJsKCNsaW5lYXJHcmFkaWVudC0xKSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTMuNTYpIi8+CiAgICAgIDxwYXRoIGQ9Ik0zMy44MyAwaDY3LjkzM2E0IDQgMCAwIDEgNCA0djkzLjM0NGE0IDQgMCAwIDEtNCA0SDMzLjgzYTQgNCAwIDAgMS00LTRWNGE0IDQgMCAwIDEgNC00eiIgZmlsbD0iI0Y1RjVGNyIvPgogICAgICA8cGF0aCBkPSJNNDIuNjc4IDkuOTUzaDUwLjIzN2EyIDIgMCAwIDEgMiAyVjM2LjkxYTIgMiAwIDAgMS0yIDJINDIuNjc4YTIgMiAwIDAgMS0yLTJWMTEuOTUzYTIgMiAwIDAgMSAyLTJ6TTQyLjk0IDQ5Ljc2N2g0OS43MTNhMi4yNjIgMi4yNjIgMCAxIDEgMCA0LjUyNEg0Mi45NGEyLjI2MiAyLjI2MiAwIDAgMSAwLTQuNTI0ek00Mi45NCA2MS41M2g0OS43MTNhMi4yNjIgMi4yNjIgMCAxIDEgMCA0LjUyNUg0Mi45NGEyLjI2MiAyLjI2MiAwIDAgMSAwLTQuNTI1ek0xMjEuODEzIDEwNS4wMzJjLS43NzUgMy4wNzEtMy40OTcgNS4zNi02LjczNSA1LjM2SDIwLjUxNWMtMy4yMzggMC01Ljk2LTIuMjktNi43MzQtNS4zNmE3LjMwOSA3LjMwOSAwIDAgMS0uMjIyLTEuNzlWNjkuNjc1aDI2LjMxOGMyLjkwNyAwIDUuMjUgMi40NDggNS4yNSA1LjQydi4wNGMwIDIuOTcxIDIuMzcgNS4zNyA1LjI3NyA1LjM3aDM0Ljc4NWMyLjkwNyAwIDUuMjc3LTIuNDIxIDUuMjc3LTUuMzkzVjc1LjFjMC0yLjk3MiAyLjM0My01LjQyNiA1LjI1LTUuNDI2aDI2LjMxOHYzMy41NjljMCAuNjE3LS4wNzcgMS4yMTYtLjIyMSAxLjc4OXoiIGZpbGw9IiNEQ0UwRTYiLz4KICAgIDwvZz4KICAgIDxwYXRoIGQ9Ik0xNDkuMTIxIDMzLjI5MmwtNi44MyAyLjY1YTEgMSAwIDAgMS0xLjMxNy0xLjIzbDEuOTM3LTYuMjA3Yy0yLjU4OS0yLjk0NC00LjEwOS02LjUzNC00LjEwOS0xMC40MDhDMTM4LjgwMiA4LjEwMiAxNDguOTIgMCAxNjEuNDAyIDAgMTczLjg4MSAwIDE4NCA4LjEwMiAxODQgMTguMDk3YzAgOS45OTUtMTAuMTE4IDE4LjA5Ny0yMi41OTkgMTguMDk3LTQuNTI4IDAtOC43NDQtMS4wNjYtMTIuMjgtMi45MDJ6IiBmaWxsPSIjRENFMEU2Ii8+CiAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDkuNjUgMTUuMzgzKSIgZmlsbD0iI0ZGRiI+CiAgICAgIDxlbGxpcHNlIGN4PSIyMC42NTQiIGN5PSIzLjE2NyIgcng9IjIuODQ5IiByeT0iMi44MTUiLz4KICAgICAgPHBhdGggZD0iTTUuNjk4IDUuNjNIMEwyLjg5OC43MDR6TTkuMjU5LjcwNGg0Ljk4NVY1LjYzSDkuMjU5eiIvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg=="
/>
<svg
height="152"
viewBox="0 0 184 152"
width="184"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
>
<g
transform="translate(24 31.67)"
>
<ellipse
cx="67.797"
cy="106.89"
fill="#F5F5F7"
fill-opacity=".8"
rx="67.797"
ry="12.668"
/>
<path
d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z"
fill="#AEB8C2"
/>
<path
d="M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z"
fill="url(#linearGradient-1)"
transform="translate(13.56)"
/>
<path
d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"
fill="#F5F5F7"
/>
<path
d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z"
fill="#DCE0E6"
/>
</g>
<path
d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z"
fill="#DCE0E6"
/>
<g
fill="#FFF"
transform="translate(149.65 15.383)"
>
<ellipse
cx="20.654"
cy="3.167"
rx="2.849"
ry="2.815"
/>
<path
d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"
/>
</g>
</g>
</svg>
</div>
</div>
`;
@ -553,10 +776,38 @@ exports[`renders ./components/empty/demo/simple.md correctly 1`] = `
<div
class="ant-empty-image"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</div>
<p
class="ant-empty-description"

View File

@ -1,16 +0,0 @@
<svg width="184" height="152" viewBox="0 0 184 152" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(24 31.67)">
<ellipse fill-opacity=".8" fill="#F5F5F7" cx="67.797" cy="106.89" rx="67.797" ry="12.668"/>
<path d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z" fill="#AEB8C2"/>
<path d="M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z" fill="url(#linearGradient-1)" transform="translate(13.56)"/>
<path d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z" fill="#F5F5F7"/>
<path d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z" fill="#DCE0E6"/>
</g>
<path d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z" fill="#DCE0E6"/>
<g transform="translate(149.65 15.383)" fill="#FFF">
<ellipse cx="20.654" cy="3.167" rx="2.849" ry="2.815"/>
<path d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,38 @@
import * as React from 'react';
const Empty = () => (
<svg width="184" height="152" viewBox="0 0 184 152" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<g transform="translate(24 31.67)">
<ellipse fillOpacity=".8" fill="#F5F5F7" cx="67.797" cy="106.89" rx="67.797" ry="12.668" />
<path
d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z"
fill="#AEB8C2"
/>
<path
d="M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z"
fill="url(#linearGradient-1)"
transform="translate(13.56)"
/>
<path
d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"
fill="#F5F5F7"
/>
<path
d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z"
fill="#DCE0E6"
/>
</g>
<path
d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z"
fill="#DCE0E6"
/>
<g transform="translate(149.65 15.383)" fill="#FFF">
<ellipse cx="20.654" cy="3.167" rx="2.849" ry="2.815" />
<path d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z" />
</g>
</g>
</svg>
);
export default Empty;

View File

@ -2,8 +2,11 @@ import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultEmptyImg from './empty.svg';
import simpleEmptyImg from './simple.svg';
import DefaultEmptyImg from './empty';
import SimpleEmptyImg from './simple';
const defaultEmptyImg = <DefaultEmptyImg />;
const simpleEmptyImg = <SimpleEmptyImg />;
export interface TransferLocale {
description: string;
@ -22,7 +25,12 @@ export interface EmptyProps {
children?: React.ReactNode;
}
const OriginEmpty: React.SFC<EmptyProps> = (props: EmptyProps) => (
interface EmptyType extends React.FC<EmptyProps> {
PRESENTED_IMAGE_DEFAULT: React.ReactNode;
PRESENTED_IMAGE_SIMPLE: React.ReactNode;
}
const Empty: EmptyType = (props: EmptyProps) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
@ -75,12 +83,6 @@ const OriginEmpty: React.SFC<EmptyProps> = (props: EmptyProps) => (
</ConfigConsumer>
);
type EmptyType = typeof OriginEmpty & {
PRESENTED_IMAGE_DEFAULT: string;
PRESENTED_IMAGE_SIMPLE: string;
};
const Empty: EmptyType = OriginEmpty as EmptyType;
Empty.PRESENTED_IMAGE_DEFAULT = defaultEmptyImg;
Empty.PRESENTED_IMAGE_SIMPLE = simpleEmptyImg;

View File

@ -1,9 +0,0 @@
<svg width="64" height="41" viewBox="0 0 64 41" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(0 1)" fill="none" fill-rule="evenodd">
<ellipse fill="#F5F5F5" cx="32" cy="33" rx="32" ry="7"/>
<g fill-rule="nonzero" stroke="#D9D9D9">
<path d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"/>
<path d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" fill="#FAFAFA"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 678 B

View File

@ -0,0 +1,18 @@
import * as React from 'react';
const Simple = () => (
<svg width="64" height="41" viewBox="0 0 64 41" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(0 1)" fill="none" fillRule="evenodd">
<ellipse fill="#F5F5F5" cx="32" cy="33" rx="32" ry="7" />
<g fillRule="nonzero" stroke="#D9D9D9">
<path d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" />
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
);
export default Simple;

View File

@ -16,6 +16,11 @@
img {
height: 100%;
}
svg {
height: 100%;
margin: auto;
}
}
&-description {

View File

@ -50,7 +50,7 @@ export default class Col extends React.Component<ColProps, {}> {
};
renderCol = ({ getPrefixCls }: ConfigConsumerProps) => {
const props: any = this.props;
const { props } = this;
const {
prefixCls: customizePrefixCls,
span,
@ -66,13 +66,14 @@ export default class Col extends React.Component<ColProps, {}> {
let sizeClassObj = {};
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
let sizeProps: ColSize = {};
if (typeof props[size] === 'number') {
sizeProps.span = props[size];
} else if (typeof props[size] === 'object') {
sizeProps = props[size] || {};
const propSize = (props as any)[size];
if (typeof propSize === 'number') {
sizeProps.span = propSize;
} else if (typeof propSize === 'object') {
sizeProps = propSize || {};
}
delete others[size];
delete (others as any)[size];
sizeClassObj = {
...sizeClassObj,
@ -100,7 +101,7 @@ export default class Col extends React.Component<ColProps, {}> {
return (
<RowContext.Consumer>
{({ gutter }) => {
let style = others.style;
let { style } = others;
if (gutter! > 0) {
style = {
paddingLeft: gutter! / 2,

View File

@ -58,7 +58,7 @@ title: Grid
</div>
</div>
In most business situations, Ant Design needs to solve a lot of information storage problems within the design area, so based on 12 Grids System, we divided the design area into 24 aliquots.
In most business situations, Ant Design needs to solve a lot of information storage problems within the design area, so based on 12 Grids System, we divided the design area into 24 sections.
We name the divided area 'box'. We suggest four boxes for horizontal arrangement at most, one at least. Boxes are proportional to the entire screen as shown in the picture above. To ensure a high level of visual comfort, we customize the typography inside of the box based on the box unit.

View File

@ -1,7 +1,7 @@
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import * as React from 'react';
import classNames from 'classnames';
import * as PropTypes from 'prop-types';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import RowContext from './RowContext';
import { tuple } from '../_util/type';
import ResponsiveObserve, {
@ -42,7 +42,9 @@ export default class Row extends React.Component<RowProps, RowState> {
state: RowState = {
screens: {},
};
token: string;
componentDidMount() {
this.token = ResponsiveObserve.subscribe(screens => {
if (typeof this.props.gutter === 'object') {
@ -50,9 +52,11 @@ export default class Row extends React.Component<RowProps, RowState> {
}
});
}
componentWillUnmount() {
ResponsiveObserve.unsubscribe(this.token);
}
getGutter(): number | undefined {
const { gutter } = this.props;
if (typeof gutter === 'object') {
@ -65,6 +69,7 @@ export default class Row extends React.Component<RowProps, RowState> {
}
return gutter as number;
}
renderRow = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,

View File

@ -61,9 +61,9 @@
}
.@{ant-prefix}-col {
position: relative;
// Prevent columns from collapsing when empty
min-height: 1px;
position: relative;
}
.make-grid-columns();

View File

@ -1,5 +1,5 @@
import Icon, { IconProps } from './index';
import * as React from 'react';
import Icon, { IconProps } from './index';
const customCache = new Set<string>();

View File

@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import * as React from 'react';
import classNames from 'classnames';
import * as allIcons from '@ant-design/icons/lib/dist';
@ -18,7 +19,27 @@ import { getTwoToneColor, setTwoToneColor } from './twoTonePrimaryColor';
ReactIcon.add(...Object.keys(allIcons).map(key => (allIcons as any)[key]));
setTwoToneColor('#1890ff');
let defaultTheme: ThemeType = 'outlined';
let dangerousTheme: ThemeType | undefined = undefined;
let dangerousTheme: ThemeType | undefined;
function unstable_ChangeThemeOfIconsDangerously(theme?: ThemeType) {
warning(
false,
'Icon',
`You are using the unstable method 'Icon.unstable_ChangeThemeOfAllIconsDangerously', ` +
`make sure that all the icons with theme '${theme}' display correctly.`,
);
dangerousTheme = theme;
}
function unstable_ChangeDefaultThemeOfIcons(theme: ThemeType) {
warning(
false,
'Icon',
`You are using the unstable method 'Icon.unstable_ChangeDefaultThemeOfIcons', ` +
`make sure that all the icons with theme '${theme}' display correctly.`,
);
defaultTheme = theme;
}
export interface TransferLocale {
icon: string;
@ -196,26 +217,6 @@ const Icon: IconComponent<IconProps> = props => {
);
};
function unstable_ChangeThemeOfIconsDangerously(theme?: ThemeType) {
warning(
false,
'Icon',
`You are using the unstable method 'Icon.unstable_ChangeThemeOfAllIconsDangerously', ` +
`make sure that all the icons with theme '${theme}' display correctly.`,
);
dangerousTheme = theme;
}
function unstable_ChangeDefaultThemeOfIcons(theme: ThemeType) {
warning(
false,
'Icon',
`You are using the unstable method 'Icon.unstable_ChangeDefaultThemeOfIcons', ` +
`make sure that all the icons with theme '${theme}' display correctly.`,
);
defaultTheme = theme;
}
Icon.createFromIconfontCN = createFromIconfontCN;
Icon.getTwoToneColor = getTwoToneColor;
Icon.setTwoToneColor = setTwoToneColor;

View File

@ -39,8 +39,11 @@ export interface InputProps
class Input extends React.Component<InputProps, any> {
static Group: typeof Group;
static Search: typeof Search;
static TextArea: typeof TextArea;
static Password: typeof Password;
static defaultProps = {
@ -88,6 +91,10 @@ class Input extends React.Component<InputProps, any> {
};
}
// Since polyfill `getSnapshotBeforeUpdate` need work with `componentDidUpdate`.
// We keep an empty function here.
componentDidUpdate() {}
getSnapshotBeforeUpdate(prevProps: InputProps) {
if (hasPrefixSuffix(prevProps) !== hasPrefixSuffix(this.props)) {
warning(
@ -99,32 +106,6 @@ class Input extends React.Component<InputProps, any> {
return null;
}
// Since polyfill `getSnapshotBeforeUpdate` need work with `componentDidUpdate`.
// We keep an empty function here.
componentDidUpdate() {}
handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
const { onPressEnter, onKeyDown } = this.props;
if (e.keyCode === 13 && onPressEnter) {
onPressEnter(e);
}
if (onKeyDown) {
onKeyDown(e);
}
};
focus() {
this.input.focus();
}
blur() {
this.input.blur();
}
select() {
this.input.select();
}
getInputClassName(prefixCls: string) {
const { size, disabled } = this.props;
return classNames(prefixCls, {
@ -134,10 +115,6 @@ class Input extends React.Component<InputProps, any> {
});
}
saveInput = (node: HTMLInputElement) => {
this.input = node;
};
setValue(
value: string,
e: React.ChangeEvent<HTMLInputElement> | React.MouseEvent<HTMLElement, MouseEvent>,
@ -166,6 +143,20 @@ class Input extends React.Component<InputProps, any> {
}
}
saveInput = (node: HTMLInputElement) => {
this.input = node;
};
handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
const { onPressEnter, onKeyDown } = this.props;
if (e.keyCode === 13 && onPressEnter) {
onPressEnter(e);
}
if (onKeyDown) {
onKeyDown(e);
}
};
handleReset = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
this.setValue('', e, () => {
this.focus();
@ -176,6 +167,18 @@ class Input extends React.Component<InputProps, any> {
this.setValue(e.target.value, e);
};
focus() {
this.input.focus();
}
blur() {
this.input.blur();
}
select() {
this.input.select();
}
renderClearIcon(prefixCls: string) {
const { allowClear } = this.props;
const { value } = this.state;
@ -257,6 +260,8 @@ class Input extends React.Component<InputProps, any> {
const affixWrapperCls = classNames(props.className, `${prefixCls}-affix-wrapper`, {
[`${prefixCls}-affix-wrapper-sm`]: props.size === 'small',
[`${prefixCls}-affix-wrapper-lg`]: props.size === 'large',
[`${prefixCls}-affix-wrapper-with-clear-btn`]:
props.suffix && props.allowClear && this.state.value,
});
return (
<span className={affixWrapperCls} style={props.style}>

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import omit from 'omit.js';
import Input, { InputProps } from './Input';
import Icon from '../icon';
@ -31,9 +32,7 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
};
onChange = () => {
this.setState({
visible: !this.state.visible,
});
this.setState(({ visible }) => ({ visible: !visible }));
};
getIcon() {
@ -59,7 +58,6 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
prefixCls,
inputPrefixCls,
size,
suffix,
visibilityToggle,
...restProps
} = this.props;
@ -69,7 +67,7 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
});
return (
<Input
{...restProps}
{...omit(restProps, ['suffix'])}
type={this.state.visible ? 'text' : 'password'}
size={size}
className={inputClassName}

View File

@ -21,6 +21,10 @@ export default class Search extends React.Component<SearchProps, any> {
private input: Input;
saveInput = (node: Input) => {
this.input = node;
};
onSearch = (e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>) => {
const { onSearch } = this.props;
if (onSearch) {
@ -37,10 +41,6 @@ export default class Search extends React.Component<SearchProps, any> {
this.input.blur();
}
saveInput = (node: Input) => {
this.input = node;
};
renderSuffix = (prefixCls: string) => {
const { suffix, enterButton } = this.props;
if (enterButton) return suffix;

View File

@ -5,21 +5,7 @@ import { polyfill } from 'react-lifecycles-compat';
import calculateNodeHeight from './calculateNodeHeight';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import ResizeObserver from '../_util/resizeObserver';
function onNextFrame(cb: () => void) {
if (window.requestAnimationFrame) {
return window.requestAnimationFrame(cb);
}
return window.setTimeout(cb, 1);
}
function clearNextFrameAction(nextFrameId: number) {
if (window.cancelAnimationFrame) {
window.cancelAnimationFrame(nextFrameId);
} else {
window.clearTimeout(nextFrameId);
}
}
import raf from '../_util/raf';
export interface AutoSizeType {
minRows?: number;
@ -36,13 +22,18 @@ export interface TextAreaProps extends HTMLTextareaProps {
export interface TextAreaState {
textareaStyles?: React.CSSProperties;
/** We need add process style to disable scroll first and then add back to avoid unexpected scrollbar */
resizing?: boolean;
}
class TextArea extends React.Component<TextAreaProps, TextAreaState> {
nextFrameActionId: number;
resizeFrameId: number;
state = {
textareaStyles: {},
resizing: false,
};
private textAreaRef: HTMLTextAreaElement;
@ -58,29 +49,13 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
}
}
resizeOnNextFrame = () => {
if (this.nextFrameActionId) {
clearNextFrameAction(this.nextFrameActionId);
}
this.nextFrameActionId = onNextFrame(this.resizeTextarea);
};
focus() {
this.textAreaRef.focus();
componentWillUnmount() {
raf.cancel(this.nextFrameActionId);
raf.cancel(this.resizeFrameId);
}
blur() {
this.textAreaRef.blur();
}
resizeTextarea = () => {
const { autosize } = this.props;
if (!autosize || !this.textAreaRef) {
return;
}
const { minRows, maxRows } = autosize as AutoSizeType;
const textareaStyles = calculateNodeHeight(this.textAreaRef, false, minRows, maxRows);
this.setState({ textareaStyles });
saveTextAreaRef = (textArea: HTMLTextAreaElement) => {
this.textAreaRef = textArea;
};
handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
@ -103,11 +78,36 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
}
};
saveTextAreaRef = (textArea: HTMLTextAreaElement) => {
this.textAreaRef = textArea;
resizeOnNextFrame = () => {
raf.cancel(this.nextFrameActionId);
this.nextFrameActionId = raf(this.resizeTextarea);
};
resizeTextarea = () => {
const { autosize } = this.props;
if (!autosize || !this.textAreaRef) {
return;
}
const { minRows, maxRows } = autosize as AutoSizeType;
const textareaStyles = calculateNodeHeight(this.textAreaRef, false, minRows, maxRows);
this.setState({ textareaStyles, resizing: true }, () => {
raf.cancel(this.resizeFrameId);
this.resizeFrameId = raf(() => {
this.setState({ resizing: false });
});
});
};
focus() {
this.textAreaRef.focus();
}
blur() {
this.textAreaRef.blur();
}
renderTextArea = ({ getPrefixCls }: ConfigConsumerProps) => {
const { textareaStyles, resizing } = this.state;
const { prefixCls: customizePrefixCls, className, disabled, autosize } = this.props;
const { ...props } = this.props;
const otherProps = omit(props, ['prefixCls', 'onPressEnter', 'autosize']);
@ -118,7 +118,8 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
const style = {
...props.style,
...this.state.textareaStyles,
...textareaStyles,
...(resizing ? { overflow: 'hidden' } : null),
};
// Fix https://github.com/ant-design/ant-design/issues/6776
// Make sure it could be reset when using form.getFieldDecorator

View File

@ -983,67 +983,90 @@ exports[`renders ./components/input/demo/password-input.md correctly 1`] = `
`;
exports[`renders ./components/input/demo/presuffix.md correctly 1`] = `
<span
class="ant-input-affix-wrapper"
>
<div>
<span
class="ant-input-prefix"
class="ant-input-affix-wrapper"
>
<i
aria-label="icon: user"
class="anticon anticon-user"
style="color:rgba(0,0,0,.25)"
<span
class="ant-input-prefix"
>
<svg
aria-hidden="true"
class=""
data-icon="user"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<i
aria-label="icon: user"
class="anticon anticon-user"
style="color:rgba(0,0,0,.25)"
>
<path
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
/>
</svg>
</i>
<svg
aria-hidden="true"
class=""
data-icon="user"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
/>
</svg>
</i>
</span>
<input
class="ant-input"
placeholder="Enter your username"
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
<i
aria-label="icon: info-circle"
class="anticon anticon-info-circle"
style="color:rgba(0,0,0,.45)"
>
<svg
aria-hidden="true"
class=""
data-icon="info-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 336a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
/>
</svg>
</i>
</span>
</span>
<input
class="ant-input"
placeholder="Enter your username"
type="text"
value=""
/>
<br />
<br />
<span
class="ant-input-suffix"
class="ant-input-affix-wrapper"
>
<i
aria-label="icon: info-circle"
class="anticon anticon-info-circle"
style="color:rgba(0,0,0,.45)"
<span
class="ant-input-prefix"
>
<svg
aria-hidden="true"
class=""
data-icon="info-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 336a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
/>
</svg>
</i>
</span>
<input
class="ant-input"
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
RMB
</span>
</span>
</span>
</div>
`;
exports[`renders ./components/input/demo/search-input.md correctly 1`] = `

View File

@ -1,6 +1,6 @@
import React from 'react';
import { mount } from 'enzyme';
/* eslint-disable import/no-unresolved */
// eslint-disable-next-line import/no-unresolved
import Form from '../../form';
import Input from '..';
import focusTest from '../../../tests/shared/focusTest';
@ -79,6 +79,7 @@ describe('TextArea', () => {
wrapper.setProps({ value: '1111' });
jest.runAllTimers();
expect(mockFunc).toHaveBeenCalledTimes(2);
expect(wrapper.find('textarea').props().style.overflow).toBeFalsy();
});
it('should support onPressEnter and onKeyDown', () => {

Some files were not shown because too many files have changed in this diff Show More