Compare commits

..

17 Commits

Author SHA1 Message Date
愚指导
97d3422043 release 2.13.13 (#9590) 2018-03-09 18:04:06 +08:00
Wei Zhu
a609518d28 Remove unsed variable 2018-03-08 17:52:58 +08:00
Wei Zhu
ef6d7a5d90 Fix upload list update logic when beforeUpload return false
Porting from 626ebf2063
2018-03-08 17:43:24 +08:00
Wei Zhu
5be1bad67f Update snapshot 2018-03-08 14:24:37 +08:00
Wei Zhu
b70fede5de correct grammar 2018-02-26 20:36:53 +08:00
Wei Zhu
358aa84fef Bump 2.13.12 2018-02-26 20:01:00 +08:00
Wei Zhu
6f716d1003 Add 2.13.12 change log 2018-02-26 20:00:36 +08:00
Wei Zhu
739c6ead54 Lock @types/react and @types/react-dom version 2018-02-26 19:46:55 +08:00
Wei Zhu
a7255ee885 Fix #8885 2018-02-26 19:21:24 +08:00
junjing.zhang
06ff0d44db fix lint fail - use babel-eslint-8.0.2 2018-01-03 19:06:37 +08:00
junjing.zhang
e96b0fc768 fix components/collapse test fail 2018-01-03 19:06:37 +08:00
junjing.zhang
8489fedb4c anchor scroll supports complete href link - test
anchor scroll supports complete href link, e.g. http://www.example.com/#id, not just #id
2018-01-03 19:06:37 +08:00
junjing.zhang
adf98d3c19 anchor scroll supports complete href link
anchor scroll supports complete href link, e.g. http://www.example.com/#id, not just #id
2018-01-03 19:06:37 +08:00
afc163
ba87b45903 Fix snapshot for moment@2.20 2017-12-17 18:57:10 +08:00
afc163
1e8830637f Fix submenu popup issue when specified unexisted defaultOpenKeys
close #8475
2017-12-17 18:54:31 +08:00
nikogu
2275195e15 bump 2.13.11 2017-12-02 17:47:19 +08:00
niko
dcf9d4c294 2.13.11 changelog (#8403) 2017-12-02 17:38:41 +08:00
635 changed files with 12532 additions and 71849 deletions

View File

@@ -1,66 +1,58 @@
# Contributing to Ant Design
[中文版](./CONTRIBUTING.zh-CN.md)
The following is a set of guidelines for contributing to Ant Design. Please spend several minutes in reading these guidelines before you create an issue or pull request.
## Code of Conduct
Anyway, these are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
We have adopted a [Code of Conduct](../CODE_OF_CONDUCT.md) that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.
## Open Development
## Do your homework before asking a question
All work on Ant Design happens directly on [GitHub](https://github.com/ant-design). Both core team members and external contributors send pull requests which go through the same review process.
It's a great idea to read Eric Steven Raymond's [How To Ask Questions The Smart Way](http://www.catb.org/esr/faqs/smart-questions.html) twice before asking a question. But if you are busy now, I recommend to read [Don't post homework questions](http://www.catb.org/esr/faqs/smart-questions.html#homework) first.
## Branch Organization
The following guidelines are about *How to avoid Homework Questions*.
According to our [release schedule](../CHANGELOG.md#release-schedule), we'll cut a `feature` branch (e.g. `feature-3.1` for 3.1 release) from `master` every month. If you send a bugfix pull request, please do it against the `master` branch, if it's a feature pull request, please do it against the `feature` branch.
### 1. Read the documentation.
## Bugs
It sad but true that someone just glance(not read) [Ant Design's documentation](http://ant.design/). Please read the documentation closely. What's more, you can modify and run our demo with [CodePen](http://codepen.io/benjycui/pen/KgPZrE?editors=001). It's helpful to understand our documentation.
We are using [GitHub Issues](https://github.com/ant-design/ant-design/issues) for bug tracing. The best way to get your bug fixed is using our [issue helper](http://new-issue.ant.design) and provide a reprduction with this [template](https://u.ant.design/codesandbox-repro).
Tips: choose the corresponding documentation with versions selector which in the bottom-right corner.
Before you reporting a bug, please make sure you've searched exists issues, and read our [FAQ](https://github.com/ant-design/ant-design/wiki/FAQ).
### 2. Make sure that your question is about Ant Design, not React
## Proposing a Change
Someone may think all of the questions that he/she meets in developing are about Ant Design, but it's not true. So, please read [React's documentation](http://facebook.github.io/react/docs/getting-started.html) or just Google (not Baidu, seriously) your questions with keyword *React* first. If you are sure that your question is about Ant Design, go ahead.
If you intend to change the public API or introduce new feature, we also recommend use our [issue helper](http://new-issue.ant.design) to create a feature request issue.
### 3. Read the FAQ and search the issues list of Ant Design
## Your First Pull Request
Your questions may be asked and solved by others. So please spend several minutes on searching. Remember [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), both code and questions.
Working on your first Pull Request? You can learn how from this free video series:
P.S.
[How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github)
1. [FAQ](https://github.com/ant-design/ant-design/wiki/FAQ)
1. [Issues list](https://github.com/ant-design/ant-design/issues)
To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first issues](https://github.com/ant-design/ant-design/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) that contain bugs or small features that have a relatively limited scope. This is a great place to get started.
## Close your issue if it's solved
If you decide to fix an issue, please be sure to check the comment thread in case somebody is already working on a fix. If nobody is working on it at the moment, please leave a comment stating that you intend to work on it so other people dont accidentally duplicate your effort.
It is a good habit which will save maintainers' time. Thank you!
If somebody claims an issue but doesnt follow up for more than two weeks, its fine to take over it but you should still leave a comment.
## Providing a demo while reporting a bug
## Sending a Pull Request
It would be helpful to provide a demo which can re-produce the bug 100%. Please fork this [CodePen](http://codepen.io/benjycui/pen/KgPZrE?editors=001) and re-produce the bug you met. Then, create an issue. The most important thing is: double check before claiming that you have found a bug.
The core team is monitoring for pull requests. We will review your pull request and either merge it, request changes to it, or close it with an explanation.
**Before submitting a pull request**, please make sure the following is done:
## Tips about Feature Request
1. Fork the repository and create your branch from [proper branch](./CONTRIBUTING.md#branch-organization).
1. Run `npm install` in the repository root.
1. If youve fixed a bug or added code that should be tested, add tests!
1. Ensure the test suite passes (npm run test). Tip: `npm test -- --watch TestName` is helpful in development.
1. Run `npm test -- -u` to update [jest snapshot](http://facebook.github.io/jest/docs/en/snapshot-testing.html#snapshot-testing-with-jest) and commit these changes as well (if has).
1. Make sure your code lints (npm run lint). Tip: Lint runs automatically when you `git commit`.
If you believe that Ant Design should provide some features, but it does not. You could create an issue to discuss. However, Ant Design is not Swiss Army Knife, there are some features which Ant Design will not support:
Sending a Pull Request to [react-component](https://github.com/react-component/):
1. Request or operate data
Since antd's components are based on react-component, sometimes you may need to send pull request to the corresponding react-component repository. If it's a bugfix pull request, after it's merged, the core team will release a patch release for that component as soon as possible, then you only need to do is reinstalling antd in your project to get the latest patch release. If it's a feature pull request, after it's merged, the core team will release a minor release, then you need raise another pull request to [Ant Design](https://github.com/ant-design/ant-design/) to update dependencies, document and TypeScript interfaces (if needed).
## Development Workflow
## Tips about Pull Request
After cloning antd, run `npm install` to fetch its dependencies. Then, you can run several commands:
**Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)
1. `npm start` runs Ant Design website locally.
1. `npm run lint` checks the code style.
1. `npm test` runs the complete test suite.
1. `npm run compile` compiles TypeScript code to the `lib` and `es` directory.
1. `npm run dist` creates UMD build of antd.
It's welcomed to pull request. And there are some tips about that:
1. It is a good habit to create a feature request issue to discuss whether the feature is necessary before you implement it. However, it's unnecessary to create an issue to claim that you found a typo or improved the readability of documentation, just create a pull request.
1. Run `npm run lint` and fix those errors before committing in order to keep consistent code style.
1. Rebase before creating a PR to keep commit history clear.
1. Add some descriptions and refer relative issues for you PR.

View File

@@ -1,64 +0,0 @@
# 贡献指南
这篇指南会指导你如何为 Ant Design 贡献一份自己的力量,请在你要提 issue 或者 pull request 之前花几分钟来阅读一遍这篇指南。
## 行为准则
我们有一份[行为准则](../CODE_OF_CONDUCT.md),希望所有的贡献者都能遵守,请花时间阅读一遍全文以确保你能明白哪些是可以做的,哪些是不可以做的。
## 透明的开发
我们所有的工作都会放在 [GitHub](https://github.com/ant-design) 上。不管是核心团队的成员还是外部贡献者的 pull request 都需要进过同样流程的 review。
## 分支管理
基于我们的[发布周期](../CHANGELOG.zh-CN.md#release-schedule), 我们每个月都会从 `master` 分支切一个 `feature` 分支出来(比如 `features-3.1` 分支用来发布 3.1 版本)。 如果你要修一个 bug那么请发 pull request 到 `master`;如果你要提一个增加新功能的 pull request那么请基于 `feature` 分支来做。
## Bugs
我们使用 [GitHub Issues](https://github.com/ant-design/ant-design/issues) 来做 bug 追踪。 如果你想要你发现的 bug 被快速解决,最好的办法就是通过我们提供的 [issue 小助手](http://new-issue.ant.design) 来提 issue。 并且能使用这个[模板](https://u.ant.design/codesandbox-repro)来提供重现。
在你报告一个 bug 之前,请先确保已经搜索过已有的 issue 和阅读了我们的[常见问题](https://github.com/ant-design/ant-design/wiki/FAQ)。
## 新增功能
如果你有改进我们的 API 或者新增功能的想法, 我们同样推荐你使用我们提供的[issue 小助手](http://new-issue.ant.design)来新建一个添加新功能的 issue。
## 第一次贡献
如果你还不清楚怎么在 GitHub 上提 Pull Request ,可以阅读下面这篇文章来学习:
[如何优雅地在 GitHub 上贡献代码](https://segmentfault.com/a/1190000000736629)
为了能帮助你开始你的第一次尝试,我们用 [good first issues](https://github.com/ant-design/ant-design/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 标记了一些比较比较容易修复的 bug 和小功能。这些 issue 可以很好地做为你的首次尝试。
如果你打算开始处理一个 issue请先检查一下 issue 下面的留言以确保没有别人正在处理这个 issue。如果当前没有人在处理的话你可以留言告知其他人你将会处理这个 issue以免别人重复劳动。
如果之前有人留言说会处理这个 issue 但是一两个星期都没有动静,那么你也可以接手处理这个 issue当然还是需要留言告知其他人。
## Pull Request
Ant Design 团队会关注所有的 pull request我们会 review 以及合并你的代码,也有可能要求你做一些修改或者告诉你我们为什么不能接受这样的修改。
**在你发送 Pull Request 之前**,请确认你是按照下面的步骤来做的:
1. 基于[正确的分支](./CONTRIBUTING.zh-CN.md#branch-organization)来做修改。
1. 在项目根目录下运行了 `npm install`
1. 如果你修复了一个 bug 或者新增了一个功能,请确保写了相应的测试, 这很重要。
1. 确认所有的测试都是通过的 `npm run test`。 小贴士:开发过程中可以用 `npm test -- --watch TestName` 来运行指定的测试。
1. 运行 `npm test -- -u` 来更新 [jest snapshot](http://facebook.github.io/jest/docs/en/snapshot-testing.html#snapshot-testing-with-jest) 并且把这些更新也提交上来(如果有的话)。
1. 确保你的代码通过了 lint 检查 `npm run lint`. 小贴士: Lint 会在你 `git commit` 的时候自动运行。
给 [react-component](https://github.com/react-component/) 发送 pull request
由于 antd 的大部分组件都是基于 react-component 的,所以有时候你可能需要给相应的 react-component 仓库发送 pull request。如果你是修复了某个 bug那么我们在合并你的修改后会尽快发布一个 patch 版本,然后你只要重新安装你的依赖就可以使用新发布的版本了。如果你的 pull request 是新增了某个功能,那么在你的修改合并并且发布版本后,你还需要发送一个 pull request 到 [Ant Design](https://github.com/ant-design/ant-design/) 来升级相应的依赖、文档以及 TypeScript 的类型定义。
## 开发流程
在你 clone 了 antd 的代码并且使用 `npm install` 安装完依赖后,你还可以运行下面几个常用的命令:
1. `npm start` 在本地运行 Ant Design 的网站。
1. `npm run lint` 检查代码风格。
1. `npm test` 运行测试。
1. `npm run compile` 编译 TypeScript 代码到 lib 和 es 目录。
1. `npm run dist` 构建 antd 的 UMD 版本到 dist 目录。

View File

@@ -42,9 +42,4 @@ module.exports = {
snapshotSerializers: [
'enzyme-to-json/serializer',
],
globals: {
'ts-jest': {
tsConfigFile: './tsconfig.test.json',
}
},
};

View File

@@ -18,9 +18,4 @@ module.exports = {
snapshotSerializers: [
'enzyme-to-json/serializer'
],
globals: {
'ts-jest': {
tsConfigFile: './tsconfig.test.json',
}
},
};

View File

@@ -16,8 +16,6 @@
"selector-list-comma-newline-after": null,
"selector-pseudo-element-colon-notation": null,
"unit-no-unknown": null,
"value-list-max-empty-lines": null,
"font-family-no-missing-generic-family-keyword": null,
"no-descending-specificity": null
"value-list-max-empty-lines": null
}
}

View File

@@ -5,24 +5,33 @@ language: node_js
node_js:
- 8
matrix:
fast_finish: true
include:
- env: TEST_TYPE=lint
- env: REACT=16 TEST_TYPE=test:dist
- env: REACT=16 TEST_TYPE=test:lib
- env: REACT=16 TEST_TYPE=test:es
- env: REACT=16 TEST_TYPE=test:dom
- env: REACT=16 TEST_TYPE=test:node
- env: REACT=15 TEST_TYPE=test:dist
- env: REACT=15 TEST_TYPE=test:lib
- env: REACT=15 TEST_TYPE=test:es
- env: REACT=15 TEST_TYPE=test:dom
- env: REACT=15 TEST_TYPE=test:node
- env: REACT=16 TEST_TYPE=bisheng:build
before_script:
- scripts/install-react.sh
env:
matrix:
- TEST_TYPE=lint
- TEST_TYPE=test:dist
- TEST_TYPE=test:lib
- TEST_TYPE=test:es
- TEST_TYPE=test:dom
- TEST_TYPE=test:node
script:
- scripts/travis-script.sh
- |
if [ "$TEST_TYPE" = lint ]; then
npm run lint
elif [ "$TEST_TYPE" = test:dist ]; then
npm run dist && \
node ./tests/dekko/dist.test.js && \
LIB_DIR=dist npm test -- -w 2
elif [ "$TEST_TYPE" = test:lib ]; then
npm run compile && \
node ./tests/dekko/lib.test.js && \
LIB_DIR=lib npm test -- -w 2
elif [ "$TEST_TYPE" = test:es ]; then
npm run compile && \
LIB_DIR=es npm test -- -w 2
elif [ "$TEST_TYPE" = test:dom ]; then
npm test -- --coverage -w 2 && \
bash <(curl -s https://codecov.io/bash)
elif [ "$TEST_TYPE" = test:node ]; then
npm run test-node -- -w 2
fi

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<p align="center">
<a href="http://ant.design">
<img width="230" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<img width="320" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg">
</a>
</p>
@@ -40,7 +40,7 @@
## 安装
```bash
npm install antd --save
npm install antd
```
## 示例
@@ -56,15 +56,28 @@ ReactDOM.render(<DatePicker />, mountNode);
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
```
你也可以[按需加载组件](https://ant.design/docs/react/getting-started-cn#按需加载)。
按需加载可通过此写法 `import DatePicker from 'antd/lib/date-picker'` 或使用 Babel 插件 [babel-plugin-import](https://github.com/ant-design/babel-plugin-import),或使用 TypeScript 插件 [ts-import-plugin](https://github.com/Brooooooklyn/ts-import-plugin)。
## TypeScript
参考 [在 TypeScript 中使用](https://ant.design/docs/react/use-in-typescript-cn)
```js
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "node",
"jsx": "preserve",
"allowSyntheticDefaultImports": true
}
}
```
> 注意:
> - 设置 `allowSyntheticDefaultImports` 避免 `error TS1192: Module 'react' has no default export` 的错误。
> - 不要使用 @types/antd, antd 已经自带了 TypeScript 定义。
## 国际化
参考 [国际化文档](http://ant.design/docs/react/i18n-cn)。
参考 [国际化文档](http://ant.design/docs/react/i18n)。
## 链接
@@ -80,7 +93,7 @@ import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
- [开发者说明](https://github.com/ant-design/ant-design/wiki/Development)
- [版本发布规则](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
- [常见问题](https://github.com/ant-design/ant-design/wiki/FAQ)
- [CodeSandbox 模板](https://u.ant.design/codesandbox-repro) for bug reports
- [CodePen 模板](http://codepen.io/benjycui/pen/KgPZrE?editors=001) for bug reports
- [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
- [定制主题](http://ant.design/docs/react/customize-theme-cn)
@@ -96,7 +109,7 @@ $ npm start
## 如何贡献
阅读我们的[贡献指南](./.github/CONTRIBUTING.md).
在任何形式的参与前,请先阅读 [贡献者文档](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md)。如果你希望参与贡献,欢迎 [Pull Request](https://github.com/ant-design/ant-design/pulls),或给我们 [报告 Bug](http://new-issue.ant.design/)。
> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。

View File

@@ -1,6 +1,6 @@
<p align="center">
<a href="http://ant.design">
<img width="230" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<img width="320" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg">
</a>
</p>
@@ -20,10 +20,6 @@ An enterprise-class UI design language and React-based implementation.
[中文 README](README-zh_CN.md)
## 3.0 Released Now! :tada::tada::tada:
[Announcing Ant Design 3.0](https://medium.com/ant-design/announcing-ant-design-3-0-70e3e65eca0c)
## Features
- An enterprise-class UI design language for web applications.
@@ -39,12 +35,12 @@ An enterprise-class UI design language and React-based implementation.
## Let's build a better antd together [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
Read our [contributing guide](./.github/CONTRIBUTING.md).
`antd` is an open source project; improvements are welcomed. If you are interested in contributing to `antd`, you can watch this repository, join in [discussion](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3ADiscussion), or try to implement some [features which have been accepted](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22PR+welcome%22). Actually, there are [many ways](https://opensource.guide/how-to-contribute/) to contribute. And we are always happy to [offer collaborator permission](https://github.com/ant-design/ant-design/issues/3222) for some active contributors.
## Install
```bash
npm install antd --save
npm install antd
```
## Usage
@@ -60,12 +56,63 @@ And import style manually:
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
```
Or [import components on demand](https://ant.design/docs/react/getting-started#Import-on-Demand)
### Use modularized antd
- Manually import
```jsx
import DatePicker from 'antd/lib/date-picker'; // for js
import 'antd/lib/date-picker/style/css'; // for css
// import 'antd/lib/date-picker/style'; // that will import less
```
- Use [babel-plugin-import](https://github.com/ant-design/babel-plugin-import)
```js
// .babelrc or babel-loader option
{
"plugins": [
["import", { "libraryName": "antd", "style": "css" }] // `style: true` for less
]
}
```
Then you can import components from antd, equivalent to import manually below.
```jsx
// import js and css modularly, parsed by babel-plugin-import
import { DatePicker } from 'antd';
```
### TypeScript
See [Use in TypeScript](https://ant.design/docs/react/use-in-typescript)
```js
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "node",
"jsx": "preserve",
"allowSyntheticDefaultImports": true
}
}
```
> Note:
> - set `allowSyntheticDefaultImports` to prevent `error TS1192: Module 'react' has no default export`.
> - Don't use @types/antd, antd provide a built-in ts definition already.
#### Use [ts-import-plugin](https://github.com/Brooooooklyn/ts-import-plugin) with modularized antd
```js
{
loader: "ts-loader", // or awesome-typescript-loader
options {
getCustomTransformers: () => ({
before: [ tsImportPluginFactory({ libraryName: "antd", style: "css" }) ]
})
}
}
```
## Internationalization
@@ -84,7 +131,7 @@ See [i18n](http://ant.design/docs/react/i18n).
- [Developer Instruction](https://github.com/ant-design/ant-design/wiki/Development)
- [Versioning Release Note](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
- [FAQ](https://github.com/ant-design/ant-design/wiki/FAQ)
- [CodeSandbox Template](https://u.ant.design/codesandbox-repro) for bug reports
- [CodePen boilerplate](http://codepen.io/benjycui/pen/KgPZrE?editors=001) for bug reports
- [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
- [Customize Theme](http://ant.design/docs/react/customize-theme)

View File

@@ -19,14 +19,12 @@ Array [
"Checkbox",
"Col",
"DatePicker",
"Divider",
"Dropdown",
"Form",
"Icon",
"Input",
"InputNumber",
"Layout",
"List",
"LocaleProvider",
"message",
"Menu",

View File

@@ -1,4 +0,0 @@
// https://github.com/moment/moment/issues/3650
export default function callMoment(moment: any, ...args: any[]) {
return (moment.default || moment)(...args);
}

View File

@@ -0,0 +1,30 @@
export function getComponentLocale(props, context, componentName, getDefaultLocale) {
let locale: any = {};
if (context && context.antLocale && context.antLocale[componentName]) {
locale = context.antLocale[componentName];
} else {
const defaultLocale = getDefaultLocale();
// TODO: make default lang of antd be English
// https://github.com/ant-design/ant-design/issues/6334
locale = defaultLocale.default || defaultLocale;
}
const result = {
...locale,
...props.locale,
};
result.lang = {
...locale.lang,
...props.locale.lang,
};
return result;
}
export function getLocaleCode(context) {
const localeCode = context.antLocale && context.antLocale.locale;
// Had use LocaleProvide but didn't set locale
if (context.antLocale && context.antLocale.exist && !localeCode) {
return 'zh-cn';
}
return localeCode;
}

View File

@@ -2,7 +2,7 @@ const availablePrefixs = ['moz', 'ms', 'webkit'];
function requestAnimationFramePolyfill() {
let lastTime = 0;
return function(callback: (n: number) => void) {
return function(callback) {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
@@ -23,11 +23,11 @@ export default function getRequestAnimationFrame() {
const prefix = availablePrefixs.filter(key => `${key}RequestAnimationFrame` in window)[0];
return prefix
? (window as any)[`${prefix}RequestAnimationFrame`]
? window[`${prefix}RequestAnimationFrame`]
: requestAnimationFramePolyfill();
}
export function cancelRequestAnimationFrame(id: number) {
export function cancelRequestAnimationFrame(id) {
if (typeof window === 'undefined') {
return null;
}
@@ -39,8 +39,6 @@ export function cancelRequestAnimationFrame(id: number) {
)[0];
return prefix ?
(
(window as any)[`${prefix}CancelAnimationFrame`] ||
(window as any)[`${prefix}CancelRequestAnimationFrame`]
).call(this, id) : clearTimeout(id);
(window[`${prefix}CancelAnimationFrame`] || window[`${prefix}CancelRequestAnimationFrame`]).call(this, id)
: clearTimeout(id);
}

View File

@@ -1,4 +1,4 @@
export default function getScroll(target: any, top: boolean): number {
export default function getScroll(target, top): number {
if (typeof window === 'undefined') {
return 0;
}

View File

@@ -1,4 +1,4 @@
let animation: boolean;
let animation;
function isCssAnimationSupported() {
if (animation !== undefined) {
@@ -11,7 +11,7 @@ function isCssAnimationSupported() {
}
if (animation !== undefined) {
for (let i = 0; i < domPrefixes.length; i++) {
if ((elm.style as any)[`${domPrefixes[i]}AnimationName`] !== undefined) {
if (elm.style[`${domPrefixes[i]}AnimationName`] !== undefined) {
animation = true;
break;
}

View File

@@ -3,18 +3,18 @@ import getRequestAnimationFrame, { cancelRequestAnimationFrame } from './getRequ
const reqAnimFrame = getRequestAnimationFrame();
function animate(node: HTMLElement, show: boolean, done: () => void) {
let height: number;
let requestAnimationFrameId: number;
function animate(node, show, done) {
let height;
let requestAnimationFrameId;
return cssAnimation(node, 'ant-motion-collapse', {
start() {
if (!show) {
node.style.height = `${node.offsetHeight}px`;
node.style.opacity = '1';
node.style.opacity = 1;
} else {
height = node.offsetHeight;
node.style.height = '0px';
node.style.opacity = '0';
node.style.height = 0;
node.style.opacity = 0;
}
},
active() {
@@ -23,7 +23,7 @@ function animate(node: HTMLElement, show: boolean, done: () => void) {
}
requestAnimationFrameId = reqAnimFrame(() => {
node.style.height = `${show ? height : 0}px`;
node.style.opacity = show ? '1' : '0';
node.style.opacity = show ? 1 : 0;
});
},
end() {
@@ -38,13 +38,13 @@ function animate(node: HTMLElement, show: boolean, done: () => void) {
}
const animation = {
enter(node: HTMLElement, done: () => void) {
enter(node, done) {
return animate(node, true, done);
},
leave(node: HTMLElement, done: () => void) {
leave(node, done) {
return animate(node, false, done);
},
appear(node: HTMLElement, done: () => void) {
appear(node, done) {
return animate(node, true, done);
},
};

View File

@@ -2,27 +2,27 @@ import getRequestAnimationFrame, { cancelRequestAnimationFrame } from '../_util/
const reqAnimFrame = getRequestAnimationFrame();
export default function throttleByAnimationFrame(fn: () => void) {
let requestId: number | null;
export default function throttleByAnimationFrame(fn) {
let requestId;
const later = (args: any[]) => () => {
const later = args => () => {
requestId = null;
fn(...args);
};
const throttled = (...args: any[]) => {
const throttled = (...args) => {
if (requestId == null) {
requestId = reqAnimFrame(later(args));
}
};
(throttled as any).cancel = () => cancelRequestAnimationFrame(requestId!);
(throttled as any).cancel = () => cancelRequestAnimationFrame(requestId);
return throttled;
}
export function throttleByAnimationFrameDecorator() {
return function(target: any, key: string, descriptor: any) {
return function(target, key, descriptor) {
let fn = descriptor.value;
let definingProperty = false;
return {

View File

@@ -1,4 +1,4 @@
export default function triggerEvent(el: Element, type: string) {
export default function triggerEvent(el, type) {
if ('createEvent' in document) {
// modern browsers, IE9+
const e = document.createEvent('HTMLEvents');

View File

@@ -60,7 +60,7 @@ describe('Affix Render', () => {
const wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
jest.runAllTimers();
wrapper.instance().affix.fixedNode.parentNode.getBoundingClientRect = jest.fn(() => {
wrapper.node.affix.refs.fixedNode.parentNode.getBoundingClientRect = jest.fn(() => {
return {
bottom: 100, height: 28, left: 0, right: 0, top: -50, width: 195,
};
@@ -71,6 +71,6 @@ describe('Affix Render', () => {
});
jest.runAllTimers();
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
expect(wrapper.node.affix.state.affixStyle).not.toBe(null);
});
});

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
@@ -8,13 +8,13 @@ import omit from 'omit.js';
import getScroll from '../_util/getScroll';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
function getTargetRect(target: HTMLElement | Window | null): ClientRect {
function getTargetRect(target): ClientRect {
return target !== window ?
(target as HTMLElement).getBoundingClientRect() :
{ top: 0, left: 0, bottom: 0 } as ClientRect;
target.getBoundingClientRect() :
{ top: 0, left: 0, bottom: 0 };
}
function getOffset(element: HTMLElement, target: HTMLElement | Window | null) {
function getOffset(element: HTMLElement, target) {
const elemRect = element.getBoundingClientRect();
const targetRect = getTargetRect(target);
@@ -55,16 +55,11 @@ export interface AffixProps {
/** 固定状态改变时触发的回调函数 */
onChange?: (affixed?: boolean) => void;
/** 设置 Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
target?: () => Window | HTMLElement | null;
target?: () => Window | HTMLElement;
prefixCls?: string;
}
export interface AffixState {
affixStyle: React.CSSProperties | undefined;
placeholderStyle: React.CSSProperties | undefined;
}
export default class Affix extends React.Component<AffixProps, AffixState> {
export default class Affix extends React.Component<AffixProps, any> {
static propTypes = {
offsetTop: PropTypes.number,
offsetBottom: PropTypes.number,
@@ -74,6 +69,9 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
scrollEvent: any;
resizeEvent: any;
timeout: any;
refs: {
fixedNode: HTMLElement;
};
events = [
'resize',
@@ -85,18 +83,17 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
'load',
];
eventHandlers: {
[key: string]: any;
} = {};
eventHandlers = {};
state: AffixState = {
affixStyle: undefined,
placeholderStyle: undefined,
};
constructor(props) {
super(props);
this.state = {
affixStyle: null,
placeholderStyle: null,
};
}
private fixedNode: HTMLElement;
setAffixStyle(e: any, affixStyle: React.CSSProperties | null) {
setAffixStyle(e, affixStyle) {
const { onChange = noop, target = getDefaultTarget } = this.props;
const originalAffixStyle = this.state.affixStyle;
const isWindow = target() === window;
@@ -106,7 +103,7 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
if (shallowequal(affixStyle, originalAffixStyle)) {
return;
}
this.setState({ affixStyle: affixStyle as React.CSSProperties }, () => {
this.setState({ affixStyle }, () => {
const affixed = !!this.state.affixStyle;
if ((affixStyle && !originalAffixStyle) ||
(!affixStyle && originalAffixStyle)) {
@@ -115,16 +112,16 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
});
}
setPlaceholderStyle(placeholderStyle: React.CSSProperties | null) {
setPlaceholderStyle(placeholderStyle) {
const originalPlaceholderStyle = this.state.placeholderStyle;
if (shallowequal(placeholderStyle, originalPlaceholderStyle)) {
return;
}
this.setState({ placeholderStyle: placeholderStyle as React.CSSProperties });
this.setState({ placeholderStyle });
}
@throttleByAnimationFrameDecorator()
updatePosition(e: any) {
updatePosition(e) {
let { offsetTop, offsetBottom, offset, target = getDefaultTarget } = this.props;
const targetNode = target();
@@ -134,8 +131,8 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
const affixNode = ReactDOM.findDOMNode(this) as HTMLElement;
const elemOffset = getOffset(affixNode, targetNode);
const elemSize = {
width: this.fixedNode.offsetWidth,
height: this.fixedNode.offsetHeight,
width: this.refs.fixedNode.offsetWidth,
height: this.refs.fixedNode.offsetHeight,
};
const offsetMode = {
@@ -157,12 +154,10 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
if (scrollTop > elemOffset.top - (offsetTop as number) && offsetMode.top) {
// Fixed Top
const width = elemOffset.width;
const top = targetRect.top + (offsetTop as number);
this.setAffixStyle(e, {
position: 'fixed',
top,
top: targetRect.top + (offsetTop as number),
left: targetRect.left + elemOffset.left,
maxHeight: `calc(100vh - ${top}px)`,
width,
});
this.setPlaceholderStyle({
@@ -205,10 +200,10 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
});
}
componentWillReceiveProps(nextProps: AffixProps) {
componentWillReceiveProps(nextProps) {
if (this.props.target !== nextProps.target) {
this.clearEventListeners();
this.setTargetEventListeners(nextProps.target!);
this.setTargetEventListeners(nextProps.target);
// Mock Event object.
this.updatePosition({});
@@ -221,7 +216,7 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
(this.updatePosition as any).cancel();
}
setTargetEventListeners(getTarget: () => HTMLElement | Window | null) {
setTargetEventListeners(getTarget) {
const target = getTarget();
if (!target) {
return;
@@ -242,10 +237,6 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
});
}
saveFixedNode = (node: HTMLDivElement) => {
this.fixedNode = node;
}
render() {
const className = classNames({
[this.props.prefixCls || 'ant-affix']: this.state.affixStyle,
@@ -255,7 +246,7 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
const placeholderStyle = { ...this.state.placeholderStyle, ...this.props.style };
return (
<div {...props} style={placeholderStyle}>
<div className={className} ref={this.saveFixedNode} style={this.state.affixStyle}>
<div className={className} ref="fixedNode" style={this.state.affixStyle}>
{this.props.children}
</div>
</div>

View File

@@ -3,5 +3,4 @@
.@{ant-prefix}-affix {
position: fixed;
z-index: @zindex-affix;
overflow: auto;
}

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import React from 'react';
import ReactDOM from 'react-dom';
import Animate from 'rc-animate';
import Icon from '../icon';
import classNames from 'classnames';

View File

@@ -1,5 +1,4 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@alert-prefix-cls: ~"@{ant-prefix}-alert";
@@ -7,71 +6,75 @@
@alert-text-color: @text-color;
.@{alert-prefix-cls} {
.reset-component;
position: relative;
padding: 8px 15px 8px 37px;
padding: 8px 48px 8px 38px;
border-radius: @border-radius-base;
color: @alert-text-color;
font-size: @font-size-base;
line-height: @line-height-base;
&&-no-icon {
padding: 8px 15px;
padding: 8px 48px 8px 16px;
}
&-icon {
top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2 + 1px;
font-size: @font-size-lg;
top: 8px + @font-size-base * @line-height-base / 2 - @font-size-lg / 2;
left: 16px;
position: absolute;
}
&-description {
font-size: @font-size-base;
line-height: 22px;
line-height: 21px;
display: none;
}
&-success {
border: @border-width-base @border-style-base ~`colorPalette("@{success-color}", 3)`;
background-color: ~`colorPalette("@{success-color}", 1)`;
border: @border-width-base @border-style-base @green-2;
background-color: @green-1;
.@{alert-prefix-cls}-icon {
color: @success-color;
}
}
&-info {
border: @border-width-base @border-style-base ~`colorPalette("@{info-color}", 3)`;
background-color: ~`colorPalette("@{info-color}", 1)`;
border: @border-width-base @border-style-base @primary-2;
background-color: @primary-1;
.@{alert-prefix-cls}-icon {
color: @info-color;
}
}
&-warning {
border: @border-width-base @border-style-base ~`colorPalette("@{warning-color}", 3)`;
background-color: ~`colorPalette("@{warning-color}", 1)`;
border: @border-width-base @border-style-base @yellow-2;
background-color: @yellow-1;
.@{alert-prefix-cls}-icon {
color: @warning-color;
}
}
&-error {
border: @border-width-base @border-style-base ~`colorPalette("@{error-color}", 3)`;
background-color: ~`colorPalette("@{error-color}", 1)`;
border: @border-width-base @border-style-base @red-2;
background-color: @red-1;
.@{alert-prefix-cls}-icon {
color: @error-color;
}
}
&-close-icon {
font-size: @font-size-sm;
font-size: @font-size-base;
position: absolute;
right: 16px;
top: 8px;
line-height: 22px;
top: 10px;
height: 12px;
line-height: 12px;
overflow: hidden;
cursor: pointer;
.@{iconfont-css-prefix}-cross {
color: @text-color-secondary;
transition: color .3s;
transition: color .3s ease;
&:hover {
color: #404040;
}
@@ -84,21 +87,21 @@
}
&-with-description {
padding: 15px 15px 15px 64px;
padding: 16px 16px 16px 60px;
position: relative;
border-radius: @border-radius-base;
color: @text-color;
line-height: @line-height-base;
line-height: 1.5;
}
&-with-description&-no-icon {
padding: 15px;
padding: 16px;
}
&-with-description &-icon {
position: absolute;
top: 16px;
left: 24px;
left: 20px;
font-size: 24px;
}

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
@@ -42,9 +42,12 @@ function easeInOutCubic(t: number, b: number, c: number, d: number) {
}
const reqAnimFrame = getRequestAnimationFrame();
function scrollTo(href: string, offsetTop = 0, target: () => Window | HTMLElement, callback = () => { }) {
const sharpMatcherRegx = /#([^#]+)$/;
function scrollTo(href: string, offsetTop = 0, target, callback = () => { }) {
const scrollTop = getScroll(target(), true);
const targetElement = document.getElementById(href.substring(1));
const sharpLinkMatch = sharpMatcherRegx.exec(href);
if (!sharpLinkMatch) { return; }
const targetElement = document.getElementById(sharpLinkMatch[1]);
if (!targetElement) {
return;
}
@@ -95,7 +98,9 @@ export default class Anchor extends React.Component<AnchorProps, any> {
antAnchor: PropTypes.object,
};
private inkNode: HTMLSpanElement;
refs: {
ink?: any;
};
private links: String[];
private scrollEvent: any;
@@ -155,7 +160,7 @@ export default class Anchor extends React.Component<AnchorProps, any> {
});
}
handleScrollTo = (link: string) => {
handleScrollTo = (link) => {
const { offsetTop, target = getDefaultTarget } = this.props;
this.animating = true;
this.setState({ activeLink: link });
@@ -172,7 +177,9 @@ export default class Anchor extends React.Component<AnchorProps, any> {
const linkSections: Array<Section> = [];
this.links.forEach(link => {
const target = document.getElementById(link.substring(1));
const sharpLinkMatch = sharpMatcherRegx.exec(link.toString());
if (!sharpLinkMatch) { return; }
const target = document.getElementById(sharpLinkMatch[1]);
if (target && getOffsetTop(target) < offsetTop + bounds) {
const top = getOffsetTop(target);
linkSections.push({
@@ -196,14 +203,10 @@ export default class Anchor extends React.Component<AnchorProps, any> {
const { prefixCls } = this.props;
const linkNode = ReactDOM.findDOMNode(this as any).getElementsByClassName(`${prefixCls}-link-title-active`)[0];
if (linkNode) {
this.inkNode.style.top = `${(linkNode as any).offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
this.refs.ink.style.top = `${(linkNode as any).offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
}
}
saveInkNode = (node: HTMLSpanElement) => {
this.inkNode = node;
}
render() {
const {
prefixCls,
@@ -230,7 +233,7 @@ export default class Anchor extends React.Component<AnchorProps, any> {
<div className={wrapperClass} style={style}>
<div className={anchorClass}>
<div className={`${prefixCls}-ink`} >
<span className={inkClass} ref={this.saveInkNode} />
<span className={inkClass} ref="ink" />
</div>
{children}
</div>

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

View File

@@ -14,7 +14,51 @@ describe('Anchor Render', () => {
wrapper.find('a[href="#API"]').simulate('click');
wrapper.instance().handleScroll();
expect(wrapper.instance().state).not.toBe(null);
wrapper.node.handleScroll();
expect(wrapper.node.state).not.toBe(null);
});
it('Anchor render perfectly for complete href - click', () => {
const wrapper = mount(
<Anchor>
<Link href="http://www.example.com/#API" title="API" />
</Anchor>
);
wrapper.find('a[href="http://www.example.com/#API"]').simulate('click');
expect(wrapper.node.state.activeLink).toBe('http://www.example.com/#API');
});
it('Anchor render perfectly for complete href - scoll', () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<div id="API">Hello</div>, { attachTo: root });
const wrapper = mount(
<Anchor>
<Link href="http://www.example.com/#API" title="API" />
</Anchor>
);
wrapper.node.handleScroll();
expect(wrapper.node.state.activeLink).toBe('http://www.example.com/#API');
});
it('Anchor render perfectly for complete href - scollTo', () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
root.id = 'root';
document.body.appendChild(root);
}
mount(<div id="API">Hello</div>, { attachTo: root });
const wrapper = mount(
<Anchor>
<Link href="##API" title="API" />
</Anchor>
);
wrapper.node.handleScrollTo('##API');
expect(wrapper.node.state.activeLink).toBe('##API');
});
});

View File

@@ -79,7 +79,7 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
</div>
`;
exports[`renders ./components/anchor/demo/static.md correctly 1`] = `
exports[`renders ./components/anchor/demo/fixed.md correctly 1`] = `
<div
class="ant-anchor-wrapper"
>

View File

@@ -1,8 +1,8 @@
---
order: 2
title:
zh-CN: 静态位置
en-US: Static Anchor
zh-CN: 固定
en-US: Fixed Anchor
---
## zh-CN

View File

@@ -1,8 +1,5 @@
import Anchor from './Anchor';
import AnchorLink from './AnchorLink';
export { AnchorProps } from './Anchor';
export { AnchorLinkProps } from './AnchorLink';
Anchor.Link = AnchorLink;
export default Anchor;

View File

@@ -1,12 +1,7 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@anchor-border-width: 2px;
.@{ant-prefix}-anchor {
.reset-component;
position: relative;
padding-left: @anchor-border-width;
&-wrapper {
background-color: @component-background;
}
@@ -19,7 +14,7 @@
&:before {
content: ' ';
position: relative;
width: @anchor-border-width;
width: 2px;
height: 100%;
display: block;
background-color: @border-color-split;
@@ -28,10 +23,10 @@
&-ball {
display: none;
position: absolute;
width: 8px;
height: 8px;
border-radius: 8px;
border: 2px solid @primary-color;
width: 9px;
height: 9px;
border-radius: 9px;
border: 3px solid @primary-color;
background-color: @component-background;
left: 50%;
transition: top .3s ease-in-out;
@@ -47,7 +42,7 @@
}
&-link {
padding: 8px 0 8px 16px;
padding: 8px 0 8px 18px;
line-height: 1;
&-title {

View File

@@ -1,22 +1,18 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import React from 'react';
import { findDOMNode } from 'react-dom';
export interface InputElementProps {
children: React.ReactElement<any>;
}
export default class InputElement extends React.Component<InputElementProps, any> {
export default class InputElement extends React.Component<any, any> {
private ele: HTMLInputElement;
focus = () => {
this.ele.focus ? this.ele.focus() : (ReactDOM.findDOMNode(this.ele) as HTMLInputElement).focus();
this.ele.focus ? this.ele.focus() : (findDOMNode(this.ele) as HTMLInputElement).focus();
}
blur = () => {
this.ele.blur ? this.ele.blur() : (ReactDOM.findDOMNode(this.ele) as HTMLInputElement).blur();
this.ele.blur ? this.ele.blur() : (findDOMNode(this.ele) as HTMLInputElement).blur();
}
saveRef = (ele: HTMLInputElement) => {
this.ele = ele;
const { ref: childRef } = this.props.children as any;
const childRef = this.props.children.ref;
if (typeof childRef === 'function') {
childRef(ele);
}

View File

@@ -3,7 +3,7 @@
exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
<div
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
style="width:200px"
style="width:200px;"
>
<div
aria-autocomplete="list"
@@ -18,7 +18,7 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
>
<div
class="ant-select-selection__placeholder"
style="display:block;user-select:none;-webkit-user-select:none"
style="display:block;user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
input here
@@ -46,7 +46,7 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
<b />
@@ -58,11 +58,11 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1`] = `
<div
class="certain-category-search-wrapper"
style="width:250px"
style="width:250px;"
>
<div
class="ant-select-lg ant-select-lg certain-category-search ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
style="width:100%"
style="width:100%;"
>
<div
aria-autocomplete="list"
@@ -77,7 +77,7 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
>
<div
class="ant-select-selection__placeholder"
style="display:block;user-select:none;-webkit-user-select:none"
style="display:block;user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
input here
@@ -116,7 +116,7 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
<b />
@@ -129,7 +129,7 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
<div
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
style="width:200px"
style="width:200px;"
>
<div
aria-autocomplete="list"
@@ -152,7 +152,7 @@ exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
<textarea
class="ant-input custom ant-select-search__field"
placeholder="input here"
style="height:50px"
style="height:50px;"
/>
<span
class="ant-select-search__field__mirror"
@@ -165,7 +165,7 @@ exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
<b />
@@ -177,7 +177,7 @@ exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly 1`] = `
<div
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
style="width:200px"
style="width:200px;"
>
<div
aria-autocomplete="list"
@@ -192,7 +192,7 @@ exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly
>
<div
class="ant-select-selection__placeholder"
style="display:block;user-select:none;-webkit-user-select:none"
style="display:block;user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
try to type \`b\`
@@ -220,7 +220,7 @@ exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
<b />
@@ -232,7 +232,7 @@ exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly
exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
<div
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
style="width:200px"
style="width:200px;"
>
<div
aria-autocomplete="list"
@@ -247,7 +247,7 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
>
<div
class="ant-select-selection__placeholder"
style="display:block;user-select:none;-webkit-user-select:none"
style="display:block;user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
input here
@@ -275,7 +275,7 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
<b />
@@ -287,11 +287,11 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly 1`] = `
<div
class="global-search-wrapper"
style="width:300px"
style="width:300px;"
>
<div
class="ant-select-lg ant-select-lg global-search ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
style="width:100%"
style="width:100%;"
>
<div
aria-autocomplete="list"
@@ -306,7 +306,7 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
>
<div
class="ant-select-selection__placeholder"
style="display:block;user-select:none;-webkit-user-select:none"
style="display:block;user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
input here
@@ -350,7 +350,7 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
<b />

View File

@@ -1,11 +1,8 @@
import React from 'react';
import { mount } from 'enzyme';
import AutoComplete from '..';
import focusTest from '../../../tests/shared/focusTest';
describe('AutoComplete with Custom Input Element Render', () => {
focusTest(AutoComplete);
it('AutoComplete with custom Input render perfectly', () => {
const wrapper = mount(
<AutoComplete dataSource={['12345', '23456', '34567']}>
@@ -15,7 +12,7 @@ describe('AutoComplete with Custom Input Element Render', () => {
expect(wrapper.find('textarea').length).toBe(1);
wrapper.find('textarea').simulate('change', { target: { value: '123' } });
const dropdownWrapper = mount(wrapper.find('Trigger').instance().getComponent());
const dropdownWrapper = mount(wrapper.find('Trigger').node.getComponent());
// should not filter data source defaultly
expect(dropdownWrapper.find('MenuItem').length).toBe(3);

View File

@@ -21,7 +21,6 @@ const dataSource = ['12345', '23456', '34567'];
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| allowClear | Show clear button, effective in multiple mode only. | boolean | false |
| autoFocus | get focus when component mounted | boolean | false |
| backfill | backfill selected item the input when using keyboard | boolean | false |
| children (for customize input element) | customize input element | HTMLInputElement / HTMLTextAreaElement / React.ReactElement<InputProps> | `<Input />` |
| children (for dataSource) | Data source for autocomplet | React.ReactElement<OptionProps> / Array&lt;React.ReactElement<OptionProps>> | - |
@@ -36,10 +35,3 @@ const dataSource = ['12345', '23456', '34567'];
| onChange | Called when select an option or input value change, or value of input is changed | function(value, label) | - |
| onSearch | Called when searching items. | function(value) | - |
| onSelect | Called when a option is selected. param is option's value and option instance. | function(value, option) | - |
## Methods
| Name | Description |
| ---- | ----------- |
| focus() | get focus |
| blur() | remove focus |

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import { Option, OptGroup } from 'rc-select';
import classNames from 'classnames';
import Select, { AbstractSelectProps, SelectValue, OptionProps, OptGroupProps } from '../select';
@@ -8,7 +8,7 @@ import InputElement from './InputElement';
export interface DataSourceItemObject { value: string; text: string; }
export type DataSourceItemType = string | DataSourceItemObject;
export interface AutoCompleteInputProps {
export interface InputProps {
onChange?: React.FormEventHandler<any>;
value: any;
}
@@ -16,7 +16,7 @@ export interface AutoCompleteInputProps {
export type ValidInputElement =
HTMLInputElement |
HTMLTextAreaElement |
React.ReactElement<AutoCompleteInputProps>;
React.ReactElement<InputProps>;
export interface AutoCompleteProps extends AbstractSelectProps {
value?: SelectValue;
@@ -34,7 +34,7 @@ function isSelectOptionOrSelectOptGroup(child: any): Boolean {
return child && child.type && (child.type.isSelectOption || child.type.isSelectOptGroup);
}
export default class AutoComplete extends React.Component<AutoCompleteProps, {}> {
export default class AutoComplete extends React.Component<AutoCompleteProps, any> {
static Option = Option as React.ClassicComponentClass<OptionProps>;
static OptGroup = OptGroup as React.ClassicComponentClass<OptGroupProps>;
@@ -47,8 +47,6 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
filterOption: false,
};
private select: any;
getInputElement = () => {
const { children } = this.props;
const element = children && React.isValidElement(children) && children.type !== Option ?
@@ -61,18 +59,6 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
);
}
focus() {
this.select.focus();
}
blur() {
this.select.blur();
}
saveSelect = (node: any) => {
this.select = node;
}
render() {
let {
size, className = '', notFoundContent, prefixCls, optionLabelProp, dataSource, children,
@@ -120,7 +106,6 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
optionLabelProp={optionLabelProp}
getInputElement={this.getInputElement}
notFoundContent={notFoundContent}
ref={this.saveSelect}
>
{options}
</Select>

View File

@@ -22,7 +22,6 @@ const dataSource = ['12345', '23456', '34567'];
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| allowClear | 支持清除, 单选模式有效 | boolean | false |
| autoFocus | 自动获取焦点 | boolean | false |
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false |
| children (自动完成的数据源) | 自动完成的数据源 | React.ReactElement<OptionProps> / Array&lt;React.ReactElement<OptionProps>> | - |
| children (自定义输入框) | 自定义输入框 | HTMLInputElement / HTMLTextAreaElement / React.ReactElement<InputProps> | `<Input />` |
@@ -37,10 +36,3 @@ const dataSource = ['12345', '23456', '34567'];
| onChange | 选中 option或 input 的 value 变化时,调用此函数 | function(value) | 无 |
| onSearch | 搜索补全项的时候调用 | function(value) | 无 |
| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | 无 |
## 方法
| 名称 | 描述 |
| ---- | ----------- |
| focus() | 获取焦点 |
| blur() | 移除焦点 |

View File

@@ -7,8 +7,6 @@
@autocomplete-prefix-cls: ~"@{select-prefix-cls}-auto-complete";
.@{autocomplete-prefix-cls} {
.reset-component;
&.@{select-prefix-cls} {
.@{select-prefix-cls} {
&-selection {

View File

@@ -3,7 +3,7 @@
exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
<div>
<span
style="margin-right:24px"
style="margin-right:24px;"
>
<span
class="ant-badge"
@@ -22,7 +22,7 @@ exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1100%);-webkit-transform:translateY(-1100%);transform:translateY(-1100%)"
style="transition:none;-ms-transform:translateY(-1100%);-webkit-transform:translateY(-1100%);transform:translateY(-1100%);"
>
<p
class=""
@@ -253,7 +253,7 @@ exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
<div>
<span
class="ant-avatar ant-avatar-lg ant-avatar-circle"
style="background-color:#f56a00;vertical-align:middle"
style="background-color:#f56a00;"
>
<span
class="ant-avatar-string"
@@ -263,7 +263,7 @@ exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
</span>
<button
class="ant-btn ant-btn-sm"
style="margin-left:16px;vertical-align:middle"
style="margin-left:16px;"
type="button"
>
<span>
@@ -309,7 +309,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
</span>
<span
class="ant-avatar ant-avatar-circle"
style="color:#f56a00;background-color:#fde3cf"
style="color:#f56a00;background-color:#fde3cf;"
>
<span
class="ant-avatar-string"
@@ -319,7 +319,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
</span>
<span
class="ant-avatar ant-avatar-circle ant-avatar-icon"
style="background-color:#87d068"
style="background-color:#87d068;"
>
<i
class="anticon anticon-user"

View File

@@ -37,12 +37,8 @@ class Autoset extends React.Component {
render() {
return (
<div>
<Avatar style={{ backgroundColor: this.state.color, verticalAlign: 'middle' }} size="large">
{this.state.user}
</Avatar>
<Button size="small" style={{ marginLeft: 16, verticalAlign: 'middle' }} onClick={this.changeUser}>
Change
</Button>
<Avatar style={{ backgroundColor: this.state.color }} size="large">{this.state.user}</Avatar>
<Button size="small" style={{ marginLeft: 16 }} onClick={this.changeUser}>Change</Button>
</div>
);
}

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import React from 'react';
import ReactDOM from 'react-dom';
import Icon from '../icon';
import classNames from 'classnames';

View File

@@ -1,10 +1,8 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@avatar-prefix-cls: ~"@{ant-prefix}-avatar";
.@{avatar-prefix-cls} {
.reset-component;
display: inline-block;
text-align: center;
background: @avatar-bg;

View File

@@ -4,7 +4,7 @@ exports[`renders ./components/back-top/demo/basic.md correctly 1`] = `
<div>
Scroll down to see the bottom-right
<strong
style="color:rgba(64, 64, 64, 0.6)"
style="color:rgba(64, 64, 64, 0.6);"
>
gray
</strong>
@@ -16,7 +16,7 @@ exports[`renders ./components/back-top/demo/custom.md correctly 1`] = `
<div>
Scroll down to see the bottom-right
<strong
style="color:#1088e9"
style="color:#1088e9;"
>
blue
</strong>

View File

@@ -15,7 +15,7 @@ describe('BackTop', () => {
const wrapper = mount(<BackTop visibilityHeight={-1} />);
document.documentElement.scrollTop = 400;
// trigger scroll manually
wrapper.instance().handleScroll();
wrapper.node.handleScroll();
jest.runAllTimers();
wrapper.find('.ant-back-top').simulate('click');
jest.runAllTimers();

View File

@@ -1,8 +1,9 @@
import * as React from 'react';
import React from 'react';
import Animate from 'rc-animate';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import omit from 'omit.js';
import Icon from '../icon';
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
@@ -108,7 +109,7 @@ export default class BackTop extends React.Component<BackTopProps, any> {
const defaultElement = (
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-icon`} />
<Icon className={`${prefixCls}-icon`} type="to-top" />
</div>
);

View File

@@ -1,10 +1,8 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@backtop-prefix-cls: ~"@{ant-prefix}-back-top";
.@{backtop-prefix-cls} {
.reset-component;
z-index: @zindex-back-top;
position: fixed;
right: 100px;
@@ -21,7 +19,6 @@
color: @back-top-color;
text-align: center;
transition: all .3s @ease-in-out;
overflow: hidden;
&:hover {
background-color: @back-top-hover-bg;
@@ -30,9 +27,7 @@
}
&-icon {
margin: 12px auto;
width: 14px;
height: 16px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAoCAYAAACWwljjAAAABGdBTUEAALGPC/xhBQAAAbtJREFUWAntmMtKw0AUhhMvS5cuxILgQlRUpIggIoKIIoigG1eC+AA+jo+i6FIXBfeuXIgoeKVeitVWJX5HWhhDksnUpp3FDPyZk3Nm5nycmZKkXhAEOXSA3lG7muTeRzmfy6HneUvIhnYkQK+Q9NhAA0Opg0vBEhjBKHiyb8iGMyQMOYuK41BcBSypAL+MYXSKjtFAW7EAGEO3qN4uMQbbAkXiSfRQJ1H6a+yhlkKRcAoVFYiweYNjtCVQJJpBz2GCiPt7fBOZQpFgDpUikse5HgnkM4Fi4QX0Fpc5wf9EbLqpUCy4jMoJSXWhFwbMNgWKhVbRhy5jirhs9fy/oFhgHVVTJEs7RLZ8sSEoJm6iz7SZDMbJ+/OKERQTttCXQRLToRUmrKWCYuA2+jbN0MB4OQobYShfdTCgn/sL1K36M7TLrN3n+758aPy2rrpR6+/od5E8tf/A1uLS9aId5T7J3CNYihkQ4D9PiMdMC7mp4rjB9kjFjZp8BlnVHJBuO1yFXIV0FdDF3RlyFdJVQBdv5AxVdIsq8apiZ2PyYO1EVykesGfZEESsCkweyR8MUW+V8uJ1gkYipmpdP1pm2aJVPEGzAAAAAElFTkSuQmCC) ~"100%/100%" no-repeat;
font-size: 20px;
margin-top: 10px;
}
}

View File

@@ -1,9 +1,9 @@
import * as React from 'react';
import React from 'react';
import { createElement, Component } from 'react';
import omit from 'omit.js';
import classNames from 'classnames';
function getNumberArray(num: string | number | undefined) {
function getNumberArray(num) {
return num ?
num.toString()
.split('')
@@ -21,12 +21,7 @@ export interface ScrollNumberProps {
title?: string | number;
}
export interface ScrollNumberState {
animateStarted?: boolean;
count?: string | number;
}
export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
export default class ScrollNumber extends Component<ScrollNumberProps, any> {
static defaultProps = {
prefixCls: 'ant-scroll-number',
count: null,
@@ -36,7 +31,7 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
lastCount: any;
constructor(props: ScrollNumberProps) {
constructor(props) {
super(props);
this.state = {
animateStarted: true,
@@ -44,14 +39,14 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
};
}
getPositionByNum(num: number, i: number) {
getPositionByNum(num, i) {
if (this.state.animateStarted) {
return 10 + num;
}
const currentDigit = getNumberArray(this.state.count)[i];
const lastDigit = getNumberArray(this.lastCount)[i];
// 同方向则在同一侧切换数字
if (this.state.count! > this.lastCount) {
if (this.state.count > this.lastCount) {
if (currentDigit >= lastDigit) {
return 10 + num;
}
@@ -63,7 +58,7 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
return num;
}
componentWillReceiveProps(nextProps: ScrollNumberProps) {
componentWillReceiveProps(nextProps) {
if ('count' in nextProps) {
if (this.state.count === nextProps.count) {
return;
@@ -90,7 +85,7 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
}
}
renderNumberList(position: number) {
renderNumberList(position) {
const childrenToReturn: React.ReactElement<any>[] = [];
for (let i = 0; i < 30; i++) {
const currentClassName = (position === i) ? 'current' : '';
@@ -99,7 +94,7 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
return childrenToReturn;
}
renderCurrentNumber(num: number, i: number) {
renderCurrentNumber(num, i) {
const position = this.getPositionByNum(num, i);
const removeTransition = this.state.animateStarted ||
(getNumberArray(this.lastCount)[i] === undefined);
@@ -117,7 +112,7 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
renderNumberElement() {
const state = this.state;
if (!state.count || isNaN(state.count as number)) {
if (!state.count || isNaN(state.count)) {
return state.count;
}
return getNumberArray(state.count)

View File

@@ -16,7 +16,7 @@ exports[`renders ./components/badge/demo/basic.md correctly 1`] = `
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%)"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%);"
>
<p
class=""
@@ -206,7 +206,7 @@ exports[`renders ./components/badge/demo/change.md correctly 1`] = `
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%)"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%);"
>
<p
class=""
@@ -383,7 +383,7 @@ exports[`renders ./components/badge/demo/change.md correctly 1`] = `
</div>
</div>
<div
style="margin-top:10px"
style="margin-top:10px;"
>
<span
class="ant-badge"
@@ -456,7 +456,7 @@ exports[`renders ./components/badge/demo/link.md correctly 1`] = `
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%)"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%);"
>
<p
class=""
@@ -620,13 +620,13 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
class="ant-badge ant-badge-not-a-wrapper"
>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
class="ant-scroll-number ant-badge-count"
data-show="true"
title="25"
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1200%);-webkit-transform:translateY(-1200%);transform:translateY(-1200%)"
style="transition:none;-ms-transform:translateY(-1200%);-webkit-transform:translateY(-1200%);transform:translateY(-1200%);"
>
<p
class=""
@@ -781,7 +781,7 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
</span>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%)"
style="transition:none;-ms-transform:translateY(-1500%);-webkit-transform:translateY(-1500%);transform:translateY(-1500%);"
>
<p
class=""
@@ -942,12 +942,12 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
<sup
class="ant-scroll-number ant-badge-count"
data-show="true"
style="background-color:#fff;color:#999;box-shadow:0 0 0 1px #d9d9d9 inset"
style="background-color:#fff;color:#999;box-shadow:0 0 0 1px #d9d9d9 inset;"
title="4"
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1400%);-webkit-transform:translateY(-1400%);transform:translateY(-1400%)"
style="transition:none;-ms-transform:translateY(-1400%);-webkit-transform:translateY(-1400%);transform:translateY(-1400%);"
>
<p
class=""
@@ -1106,9 +1106,9 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
class="ant-badge ant-badge-not-a-wrapper"
>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
class="ant-scroll-number ant-badge-count"
data-show="true"
style="background-color:#52c41a"
style="background-color:#87d068;"
title="109"
>
99+
@@ -1127,13 +1127,13 @@ exports[`renders ./components/badge/demo/overflow.md correctly 1`] = `
href="#"
/>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
class="ant-scroll-number ant-badge-count"
data-show="true"
title="99"
>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1900%);-webkit-transform:translateY(-1900%);transform:translateY(-1900%)"
style="transition:none;-ms-transform:translateY(-1900%);-webkit-transform:translateY(-1900%);transform:translateY(-1900%);"
>
<p
class=""
@@ -1288,7 +1288,7 @@ exports[`renders ./components/badge/demo/overflow.md correctly 1`] = `
</span>
<span
class="ant-scroll-number-only"
style="transition:none;-ms-transform:translateY(-1900%);-webkit-transform:translateY(-1900%);transform:translateY(-1900%)"
style="transition:none;-ms-transform:translateY(-1900%);-webkit-transform:translateY(-1900%);transform:translateY(-1900%);"
>
<p
class=""
@@ -1451,7 +1451,7 @@ exports[`renders ./components/badge/demo/overflow.md correctly 1`] = `
href="#"
/>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
class="ant-scroll-number ant-badge-count"
data-show="true"
title="100"
>
@@ -1466,7 +1466,7 @@ exports[`renders ./components/badge/demo/overflow.md correctly 1`] = `
href="#"
/>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
class="ant-scroll-number ant-badge-count"
data-show="true"
title="99"
>
@@ -1481,7 +1481,7 @@ exports[`renders ./components/badge/demo/overflow.md correctly 1`] = `
href="#"
/>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
class="ant-scroll-number ant-badge-count"
data-show="true"
title="1000"
>

View File

@@ -30,12 +30,12 @@ ReactDOM.render(
<style>
.ant-badge:not(.ant-badge-status) {
margin-right: 20px;
margin-right: 16px;
}
.head-example {
width: 42px;
height: 42px;
border-radius: 4px;
border-radius: 6px;
background: #eee;
display: inline-block;
}

View File

@@ -22,7 +22,7 @@ ReactDOM.render(
<div>
<Badge count={25} />
<Badge count={4} style={{ backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset' }} />
<Badge count={109} style={{ backgroundColor: '#52c41a' }} />
<Badge count={109} style={{ backgroundColor: '#87d068' }} />
</div>
, mountNode);
````

View File

@@ -30,4 +30,3 @@ Badge normally appears in proximity to notifications or user avatars with eye-ca
| showZero | Whether to show badge when `count` is zero | boolean | `false` |
| status | Set Badge as a status dot | `success` \| `processing` \| `default` \| `error` \| `warning` | `''` |
| text | If `status` is set, `text` sets the display text of the status `dot` | string | `''` |
| offset | set offset of the badge dot, like [x, y] | [number, number] | - |

View File

@@ -1,10 +1,9 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import Animate from 'rc-animate';
import ScrollNumber from './ScrollNumber';
import classNames from 'classnames';
export { ScrollNumberProps } from './ScrollNumber';
import warning from '../_util/warning';
export interface BadgeProps {
/** Number to show in badge */
@@ -20,7 +19,6 @@ export interface BadgeProps {
className?: string;
status?: 'success' | 'processing' | 'default' | 'error' | 'warning';
text?: string;
offset?: [number | string, number | string];
}
export default class Badge extends React.Component<BadgeProps, any> {
@@ -56,7 +54,6 @@ export default class Badge extends React.Component<BadgeProps, any> {
dot,
status,
text,
offset,
...restProps,
} = this.props;
const isDot = dot || status;
@@ -69,29 +66,27 @@ export default class Badge extends React.Component<BadgeProps, any> {
const isZero = displayCount === '0' || displayCount === 0;
const isEmpty = displayCount === null || displayCount === undefined || displayCount === '';
const hidden = (isEmpty || (isZero && !showZero)) && !isDot;
const statusCls = classNames({
[`${prefixCls}-status-dot`]: !!status,
[`${prefixCls}-status-${status}`]: !!status,
});
const scrollNumberCls = classNames({
[`${prefixCls}-dot`]: isDot,
[`${prefixCls}-count`]: !isDot,
[`${prefixCls}-multiple-words`]: count && count.toString && count.toString().length > 1,
[`${prefixCls}-status-${status}`]: !!status,
});
const badgeCls = classNames(className, prefixCls, {
[`${prefixCls}-status`]: !!status,
[`${prefixCls}-not-a-wrapper`]: !children,
});
const styleWithOffset = offset ? {
marginTop: offset[0],
marginLeft: offset[1],
...style,
} : style;
warning(
!(children && status),
'`Badge[children]` and `Badge[status]` cannot be used at the same time.',
);
// <Badge status="success" />
if (!children && status) {
const statusCls = classNames({
[`${prefixCls}-status-dot`]: !!status,
[`${prefixCls}-status-${status}`]: true,
});
return (
<span className={badgeCls} style={styleWithOffset}>
<span className={badgeCls}>
<span className={statusCls} />
<span className={`${prefixCls}-status-text`}>{text}</span>
</span>
@@ -105,7 +100,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
className={scrollNumberCls}
count={displayCount}
title={count}
style={styleWithOffset}
style={style}
/>
);

View File

@@ -31,4 +31,3 @@ title: Badge
| showZero | 当数值为 0 时,是否展示 Badge | boolean | false |
| status | 设置 Badge 为状态点 | Enum{ 'success', 'processing, 'default', 'error', 'warning' } | '' |
| text | 在设置了 `status` 的前提下有效,设置状态点的文本 | string | '' |
| offset | 设置状态点的位置偏移,格式为 [x, y] | [number, number] | - |

View File

@@ -1,11 +1,9 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@badge-prefix-cls: ~"@{ant-prefix}-badge";
@number-prefix-cls: ~"@{ant-prefix}-scroll-number";
.@{badge-prefix-cls} {
.reset-component;
position: relative;
display: inline-block;
line-height: 1;
@@ -26,17 +24,13 @@
font-size: @badge-font-size;
white-space: nowrap;
transform-origin: -10% center;
box-shadow: 0 0 0 1px #fff;
font-family: tahoma;
a,
a:hover {
color: #fff;
}
}
&-multiple-words {
padding: 0 8px;
}
&-dot {
position: absolute;
transform: translateX(-50%);
@@ -55,19 +49,16 @@
vertical-align: baseline;
&-dot {
width: @badge-status-size;
height: @badge-status-size;
width: 8px;
height: 8px;
display: inline-block;
border-radius: 50%;
vertical-align: middle;
position: relative;
top: -1px;
}
&-success {
background-color: @success-color;
}
&-processing {
background-color: @processing-color;
background-color: @primary-color;
position: relative;
&:after {
position: absolute;
@@ -76,7 +67,7 @@
width: 100%;
height: 100%;
border-radius: 50%;
border: 1px solid @processing-color;
border: 1px solid @primary-color;
content: '';
animation: antStatusProcessing 1.2s infinite ease-in-out;
}
@@ -108,7 +99,7 @@
animation-fill-mode: both;
}
&-not-a-wrapper .@{ant-prefix}-scroll-number {
&-not-a-wrapper &-count {
top: auto;
display: block;
position: relative;
@@ -135,7 +126,6 @@
height: @badge-height;
> p {
height: @badge-height;
margin: 0;
}
}
}

View File

@@ -1,26 +1,21 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { cloneElement } from 'react';
import warning from '../_util/warning';
import BreadcrumbItem from './BreadcrumbItem';
import classNames from 'classnames';
export interface Route {
path: string;
breadcrumbName: string;
}
export interface BreadcrumbProps {
prefixCls?: string;
routes?: Route[];
params?: any;
routes?: Array<any>;
params?: Object;
separator?: React.ReactNode;
itemRender?: (route: any, params: any, routes: Array<any>, paths: Array<string>) => React.ReactNode;
style?: React.CSSProperties;
className?: string;
}
function getBreadcrumbName(route: Route, params: any) {
function getBreadcrumbName(route, params) {
if (!route.breadcrumbName) {
return null;
}
@@ -32,7 +27,7 @@ function getBreadcrumbName(route: Route, params: any) {
return name;
}
function defaultItemRender(route: Route, params: any, routes: Route[], paths: string[]) {
function defaultItemRender(route, params, routes, paths) {
const isLastItem = routes.indexOf(route) === routes.length - 1;
const name = getBreadcrumbName(route, params);
return isLastItem

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';
export interface BreadcrumbItemProps {

View File

@@ -1,3 +1,11 @@
import { render } from 'enzyme';
import demoTest from '../../../tests/shared/demoTest';
import routerDemo from '../demo/router.md';
demoTest('breadcrumb', { skip: ['router.md', 'router-4.md'] });
const testMethod = typeof window !== 'undefined' ? test : test.skip;
testMethod('renders ./components/breadcrumb/demo/router.md correctly', () => {
const wrapper = render(routerDemo);
expect(wrapper).toMatchSnapshot();
});

View File

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

View File

@@ -1,18 +1,13 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@breadcrumb-prefix-cls: ~"@{ant-prefix}-breadcrumb";
.@{breadcrumb-prefix-cls} {
.reset-component;
color: @text-color-secondary;
.@{iconfont-css-prefix} {
font-size: @font-size-sm;
}
color: @text-color;
font-size: @font-size-base;
a {
color: @text-color-secondary;
color: @text-color;
transition: color .3s;
&:hover {
color: @primary-5;
@@ -20,6 +15,7 @@
}
& > span:last-child {
font-weight: 500;
color: @text-color;
}
@@ -28,8 +24,8 @@
}
&-separator {
margin: 0 @padding-xs;
color: @text-color-secondary;
margin: 0 8px;
color: rgba(0, 0, 0, 0.3);
}
&-link {

View File

@@ -251,7 +251,7 @@ exports[`renders ./components/button/demo/disabled.md correctly 1`] = `
exports[`renders ./components/button/demo/ghost.md correctly 1`] = `
<div
style="background:rgb(190, 200, 200);padding:26px 16px 16px"
style="background:rgb(190, 200, 200);padding:26px 16px 16px;"
>
<button
class="ant-btn ant-btn-primary ant-btn-background-ghost"

View File

@@ -49,15 +49,3 @@ exports[`Button renders correctly 1`] = `
</span>
</button>
`;
exports[`Button should support link button 1`] = `
<a
class="ant-btn"
href="http://ant.design"
target="_blank"
>
<span>
link button
</span>
</a>
`;

View File

@@ -52,7 +52,7 @@ describe('Button', () => {
<DefaultButton />
);
wrapper.simulate('click');
expect(wrapper.find('.ant-btn-loading').length).toBe(1);
expect(wrapper.hasClass('ant-btn-loading')).toBe(true);
});
it('should change loading state with delay', () => {
@@ -74,11 +74,4 @@ describe('Button', () => {
wrapper.simulate('click');
expect(wrapper.hasClass('ant-btn-loading')).toBe(false);
});
it('should support link button', () => {
const wrapper = mount(
<Button target="_blank" href="http://ant.design">link button</Button>
);
expect(wrapper.render()).toMatchSnapshot();
});
});

View File

@@ -1,6 +1,7 @@
import * as React from 'react';
import React from 'react';
import classNames from 'classnames';
import { ButtonSize } from './button';
export type ButtonSize = 'small' | 'large';
export interface ButtonGroupProps {
size?: ButtonSize;

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import omit from 'omit.js';
@@ -52,9 +52,6 @@ export interface ButtonProps {
prefixCls?: string;
className?: string;
ghost?: boolean;
target?: string;
href?: string;
download?: string;
}
export default class Button extends React.Component<ButtonProps, any> {
@@ -98,7 +95,7 @@ export default class Button extends React.Component<ButtonProps, any> {
}
if (typeof loading !== 'boolean' && loading && loading.delay) {
this.delayTimeout = window.setTimeout(() => this.setState({ loading }), loading.delay);
this.delayTimeout = setTimeout(() => this.setState({ loading }), loading.delay);
} else {
this.setState({ loading });
}
@@ -117,7 +114,7 @@ export default class Button extends React.Component<ButtonProps, any> {
// Add click effect
this.setState({ clicked: true });
clearTimeout(this.timeout);
this.timeout = window.setTimeout(() => this.setState({ clicked: false }), 500);
this.timeout = setTimeout(() => this.setState({ clicked: false }), 500);
const onClick = this.props.onClick;
if (onClick) {
@@ -145,8 +142,6 @@ export default class Button extends React.Component<ButtonProps, any> {
break;
}
const ComponentProp = others.href ? 'a' : 'button';
const classes = classNames(prefixCls, className, {
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${shape}`]: shape,
@@ -160,17 +155,17 @@ export default class Button extends React.Component<ButtonProps, any> {
const iconType = loading ? 'loading' : icon;
const iconNode = iconType ? <Icon type={iconType} /> : null;
const needInserted = React.Children.count(children) === 1 && (!iconType || iconType === 'loading');
const kids = children ? React.Children.map(children, child => insertSpace(child, needInserted)) : null;
const kids = React.Children.map(children, child => insertSpace(child, needInserted));
return (
<ComponentProp
<button
{...omit(others, ['loading'])}
type={others.href ? undefined : (htmlType || 'button')}
type={htmlType || 'button'}
className={classes}
onClick={this.handleClick}
>
{iconNode}{kids}
</ComponentProp>
</button>
);
}
}

View File

@@ -24,13 +24,9 @@ To get a customized button, just set `type`/`shape`/`size`/`loading`/`disabled`.
| size | can be set to `small` `large` or omitted | string | `default` |
| type | can be set to `primary` `ghost` `dashed` `danger`(added in 2.7) or omitted (meaning `default`) | string | `default` |
| onClick | set the handler to handle `click` event | function | - |
| href | redirect url of link button | string | - |
| target | same as target attribute of a, works when href is specified | string | - |
`<Button>Hello world!</Button>` will be rendered into `<button><span>Hello world!</span></button>`, and all the properties which are not listed above will be transferred to the `<button>` tag.
`<Button href="http://example.com">Hello world!</Button>` will be rendered into `<a href="http://example.com"><span>Hello world!</span></a>`.
<style>
[id^=components-button-demo-] .ant-btn {
margin-right: 8px;

View File

@@ -1,8 +1,5 @@
import Button from './button';
import ButtonGroup from './button-group';
export { ButtonProps, ButtonShape, ButtonSize, ButtonType } from './button';
export { ButtonGroupProps } from './button-group';
Button.Group = ButtonGroup;
export default Button;

View File

@@ -27,14 +27,9 @@ subtitle: 按钮
| size | 设置按钮大小,可选值为 `small` `large` 或者不设 | string | `default` |
| type | 设置按钮类型,可选值为 `primary` `dashed` `danger`(版本 2.7 中增加) 或者不设 | string | - |
| onClick | `click` 事件的 handler | function | - |
| href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - |
| target | 相当于 a 链接的 target 属性href 存在时生效 | string | - |
`<Button>Hello world!</Button>` 最终会被渲染为 `<button><span>Hello world!</span></button>`,并且除了上表中的属性,其它属性都会直接传到 `<button></button>`
`<Button href="http://example.com">Hello world!</Button>` 则会渲染为 `<a href="http://example.com"><span>Hello world!</span></a>`
<style>
[id^="components-button-demo-"] .ant-btn {
margin-right: 8px;

View File

@@ -12,7 +12,6 @@
// Button styles
// -----------------------------
.@{btn-prefix-cls} {
.reset-component;
.btn;
.btn-default;
@@ -128,7 +127,7 @@
// To ensure that a space will be placed between character and `Icon`.
> .@{iconfont-css-prefix} + span,
> span + .@{iconfont-css-prefix} {
margin-left: 8px;
margin-left: 0.5em;
}
&-clicked:after {
@@ -174,13 +173,3 @@
border-width: 6px;
}
}
a.@{btn-prefix-cls} {
line-height: @btn-height-base - 2px;
&-lg {
line-height: @btn-height-lg - 2px;
}
&-sm {
line-height: @btn-height-sm - 2px;
}
}

View File

@@ -40,7 +40,7 @@
&:hover,
&:focus {
.button-color(@primary-5; @background; @primary-5);
.button-color(@primary-color; @background; @primary-color);
}
&:active,
@@ -56,12 +56,12 @@
&:hover,
&:focus {
.button-color(@btn-primary-color; ~`colorPalette("@{color}", 5)`; ~`colorPalette("@{color}", 5)`);
.button-color(@btn-primary-color; @color; @color;);
}
&:active,
&.active {
.button-color(@btn-primary-color; ~`colorPalette("@{color}", 7)`; ~`colorPalette("@{color}", 7)`);
.button-color(@btn-primary-color; ~`colorPalette("@{color}", 7)`; ~`colorPalette("@{color}", 7)`;);
}
.button-disabled();
@@ -185,7 +185,7 @@
}
&-sm {
.button-size(@btn-height-sm; @btn-padding-sm; @btn-font-size-sm; @btn-border-radius-sm);
.button-size(@btn-height-sm; @btn-padding-sm; @font-size-base; @btn-border-radius-sm);
}
}
@@ -251,6 +251,8 @@
.@{btnClassName}:not(:first-child):not(:last-child) {
border-radius: 0;
padding-left: 8px;
padding-right: 8px;
}
> .@{btnClassName}:first-child {
@@ -258,12 +260,14 @@
&:not(:last-child) {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
padding-right: 8px;
}
}
> .@{btnClassName}:last-child:not(:first-child) {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
padding-left: 8px;
}
& > & {

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import * as moment from 'moment';
import React from 'react';
import moment from 'moment';
import { PREFIX_CLS } from './Constants';
import Select from '../select';
import { Group, Button } from '../radio';
@@ -12,7 +12,7 @@ export interface HeaderProps {
yearSelectOffset?: number;
yearSelectTotal?: number;
type?: string;
onValueChange?: (value: moment.Moment) => void;
onValueChange?: (value) => void;
onTypeChange?: (type: string) => void;
value: any;
}
@@ -24,9 +24,9 @@ export default class Header extends React.Component<HeaderProps, any> {
yearSelectTotal: 20,
};
private calenderHeaderNode: HTMLDivElement;
calenderHeaderNode: any;
getYearSelectElement(year: number) {
getYearSelectElement(year) {
const { yearSelectOffset, yearSelectTotal, locale, prefixCls, fullscreen } = this.props;
const start = year - (yearSelectOffset as number);
const end = start + (yearSelectTotal as number);
@@ -61,7 +61,7 @@ export default class Header extends React.Component<HeaderProps, any> {
return months;
}
getMonthSelectElement(month: number, months: number[]) {
getMonthSelectElement(month, months) {
const props = this.props;
const { prefixCls, fullscreen } = props;
const options: React.ReactElement<any>[] = [];
@@ -84,7 +84,7 @@ export default class Header extends React.Component<HeaderProps, any> {
);
}
onYearChange = (year: string) => {
onYearChange = (year) => {
const newValue = this.props.value.clone();
newValue.year(parseInt(year, 10));
@@ -94,7 +94,7 @@ export default class Header extends React.Component<HeaderProps, any> {
}
}
onMonthChange = (month: string) => {
onMonthChange = (month) => {
const newValue = this.props.value.clone();
newValue.month(parseInt(month, 10));
const onValueChange = this.props.onValueChange;
@@ -103,14 +103,14 @@ export default class Header extends React.Component<HeaderProps, any> {
}
}
onTypeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onTypeChange = (e) => {
const onTypeChange = this.props.onTypeChange;
if (onTypeChange) {
onTypeChange(e.target.value);
}
}
getCalenderHeaderNode = (node: HTMLDivElement) => {
getCalenderHeaderNode = (node) => {
this.calenderHeaderNode = node;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
---
order: 2
title:
title:
zh-CN: 卡片模式
en-US: Card
---
@@ -21,7 +21,7 @@ function onPanelChange(value, mode) {
}
ReactDOM.render(
<div style={{ width: 300, border: '1px solid #d9d9d9', borderRadius: 4 }}>
<div style={{ width: 290, border: '1px solid #d9d9d9', borderRadius: 4 }}>
<Calendar fullscreen={false} onPanelChange={onPanelChange} />
</div>
, mountNode);

View File

@@ -14,7 +14,7 @@ title:
This component can be rendered by using `dateCellRender` and `monthCellRender` with the data you need.
````jsx
import { Calendar, Badge } from 'antd';
import { Calendar } from 'antd';
function getListData(value) {
let listData;
@@ -22,18 +22,18 @@ function getListData(value) {
case 8:
listData = [
{ type: 'warning', content: 'This is warning event.' },
{ type: 'success', content: 'This is usual event.' },
{ type: 'normal', content: 'This is usual event.' },
]; break;
case 10:
listData = [
{ type: 'warning', content: 'This is warning event.' },
{ type: 'success', content: 'This is usual event.' },
{ type: 'normal', content: 'This is usual event.' },
{ type: 'error', content: 'This is error event.' },
]; break;
case 15:
listData = [
{ type: 'warning', content: 'This is warning event' },
{ type: 'success', content: 'This is very long usual event。。....' },
{ type: 'normal', content: 'This is very long usual event。。....' },
{ type: 'error', content: 'This is error event 1.' },
{ type: 'error', content: 'This is error event 2.' },
{ type: 'error', content: 'This is error event 3.' },
@@ -51,7 +51,8 @@ function dateCellRender(value) {
{
listData.map(item => (
<li key={item.content}>
<Badge status={item.type} text={item.content} />
<span className={`event-${item.type}`}>●</span>
{item.content}
</li>
))
}
@@ -82,20 +83,42 @@ ReactDOM.render(
````css
.events {
line-height: 24px;
list-style: none;
margin: 0;
padding: 0;
}
.events .ant-badge-status {
.events li {
color: #999;
overflow: hidden;
white-space: nowrap;
width: 100%;
text-overflow: ellipsis;
font-size: 12px;
white-space: nowrap;
}
.events li span {
vertical-align: middle;
}
.events li span:first-child {
font-size: 9px;
margin-right: 4px;
}
.event-warning {
color: #fac450;
}
.event-normal {
color: #108ee9;
}
.event-error {
color: #f50;
}
.notes-month {
text-align: center;
font-size: 28px;
}
.notes-month section {
font-size: 28px;

View File

@@ -16,10 +16,11 @@ When data is in the form of dates, such as schedules, timetables, prices calenda
**Note:** Part of the Calendar's locale is read from `value`. So, please set the locale of `moment` correctly.
```jsx
// The default locale is en-US, if you want to use other locale, just set locale in entry file globaly.
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
import moment from 'moment';
// It's recommended to set locale in entry file globaly.
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
<Calendar
dateCellRender={dateCellRender}

View File

@@ -1,25 +1,27 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import * as moment from 'moment';
import moment from 'moment';
import FullCalendar from 'rc-calendar/lib/FullCalendar';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { PREFIX_CLS } from './Constants';
import Header from './Header';
import callMoment from '../_util/callMoment';
import { getComponentLocale, getLocaleCode } from '../_util/getLocale';
declare const require: Function;
export { HeaderProps } from './Header';
function noop() { return null; }
function zerofixed(v: number) {
function zerofixed(v) {
if (v < 10) {
return `0${v}`;
}
return `${v}`;
}
export interface CalendarContext {
antLocale?: {
Calendar?: any,
};
}
export type CalendarMode = 'month' | 'year';
export interface CalendarProps {
@@ -41,7 +43,7 @@ export interface CalendarProps {
}
export interface CalendarState {
value: moment.Moment;
value?: moment.Moment;
mode?: CalendarMode;
}
@@ -70,10 +72,18 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
onSelect: PropTypes.func,
};
constructor(props: CalendarProps) {
super(props);
static contextTypes = {
antLocale: PropTypes.object,
};
const value = props.value || props.defaultValue || callMoment(moment);
context: CalendarContext;
constructor(props, context) {
super(props, context);
// Make sure that moment locale had be set correctly.
getComponentLocale(props, context, 'Calendar', () => require('./locale/zh_CN'));
const value = props.value || props.defaultValue || moment();
if (!moment.isMoment(value)) {
throw new Error(
'The value/defaultValue of Calendar must be a moment object after `antd@2.0`, ' +
@@ -89,12 +99,12 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
componentWillReceiveProps(nextProps: CalendarProps) {
if ('value' in nextProps) {
this.setState({
value: nextProps.value!,
value: nextProps.value,
});
}
}
monthCellRender = (value: moment.Moment) => {
monthCellRender = (value) => {
const { prefixCls, monthCellRender = noop as Function } = this.props;
return (
<div className={`${prefixCls}-month`}>
@@ -108,7 +118,7 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
);
}
dateCellRender = (value: moment.Moment) => {
dateCellRender = (value) => {
const { prefixCls, dateCellRender = noop as Function } = this.props;
return (
<div className={`${prefixCls}-date`}>
@@ -122,12 +132,7 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
);
}
getDefaultLocale() {
const locale = require('./locale/en_US');
return locale.default || locale;
}
setValue = (value: moment.Moment, way: 'select' | 'changePanel') => {
setValue = (value, way: 'select' | 'changePanel') => {
if (!('value' in this.props)) {
this.setState({ value });
}
@@ -140,7 +145,7 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
}
}
setType = (type: string) => {
setType = (type) => {
const mode = (type === 'date') ? 'month' : 'year';
if (this.state.mode !== mode) {
this.setState({ mode });
@@ -148,33 +153,35 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
}
}
onHeaderValueChange = (value: moment.Moment) => {
onHeaderValueChange = (value) => {
this.setValue(value, 'changePanel');
}
onHeaderTypeChange = (type: string) => {
onHeaderTypeChange = (type) => {
this.setType(type);
}
onPanelChange(value: moment.Moment, mode: CalendarMode | undefined) {
onPanelChange(value, mode) {
const { onPanelChange } = this.props;
if (onPanelChange) {
onPanelChange(value, mode);
}
}
onSelect = (value: moment.Moment) => {
onSelect = (value) => {
this.setValue(value, 'select');
}
renderCalendar = (locale: any, localeCode: string) => {
const { state, props } = this;
render() {
const { state, props, context } = this;
const { value, mode } = state;
const localeCode = getLocaleCode(context);
if (value && localeCode) {
value.locale(localeCode);
}
const { prefixCls, style, className, fullscreen, dateFullCellRender, monthFullCellRender } = props;
const type = (mode === 'year') ? 'month' : 'date';
const locale = getComponentLocale(props, context, 'Calendar', () => require('./locale/zh_CN'));
let cls = className || '';
if (fullscreen) {
@@ -210,15 +217,4 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
</div>
);
}
render() {
return (
<LocaleReceiver
componentName="Calendar"
defaultLocale={this.getDefaultLocale}
>
{this.renderCalendar}
</LocaleReceiver>
);
}
}

View File

@@ -17,10 +17,11 @@ title: Calendar
**注意:**Calendar 部分 locale 是从 value 中读取,所以请先正确设置 moment 的 locale。
```jsx
// 默认语言为 en-US所以如果需要使用其他语言推荐在入口文件全局设置 locale
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
import moment from 'moment';
// 推荐在入口文件全局设置 locale
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
<Calendar
dateCellRender={dateCellRender}

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@full-calendar-prefix-cls: ~"@{ant-prefix}-fullcalendar";
.@{full-calendar-prefix-cls} {
.reset-component;
font-size: @font-size-base;
line-height: @line-height-base;
outline: none;
border-top: @border-width-base @border-style-base @border-color-base;
@@ -38,7 +38,7 @@
}
&-calendar-body {
padding: 8px 12px;
padding: 8px 8px 14px;
}
table {
@@ -46,7 +46,7 @@
max-width: 100%;
background-color: transparent;
width: 100%;
height: 256px;
height: 246px;
}
table,
@@ -91,12 +91,12 @@
display: block;
margin: 0 auto;
color: @text-color;
border-radius: @border-radius-sm;
width: 24px;
height: 24px;
border-radius: @border-radius-base;
width: 22px;
height: 22px;
padding: 0;
background: transparent;
line-height: 24px;
line-height: 22px;
transition: all .3s;
&:hover {
@@ -116,7 +116,7 @@
&-today &-value,
&-month-panel-current-cell &-value {
box-shadow: 0 0 0 1px @primary-color inset;
box-shadow: 0 0 0 1px @primary-color;
}
&-selected-day &-value,

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import classNames from 'classnames';
export interface CardGridProps {

View File

@@ -1,31 +0,0 @@
import * as React from 'react';
import classNames from 'classnames';
export interface CardMetaProps {
prefixCls?: string;
style?: React.CSSProperties;
className?: string;
avatar?: React.ReactNode;
title?: React.ReactNode;
description?: React.ReactNode;
}
export default (props: CardMetaProps) => {
const { prefixCls = 'ant-card', className, avatar, title, description, ...others } = props;
const classString = classNames(`${prefixCls}-meta`, className);
const avatarDom = avatar ? <div className={`${prefixCls}-meta-avatar`}>{avatar}</div> : null;
const titleDom = title ? <div className={`${prefixCls}-meta-title`}>{title}</div> : null;
const descriptionDom = description ?
<div className={`${prefixCls}-meta-description`}>{description}</div> : null;
const MetaDetail = titleDom || descriptionDom ?
<div className={`${prefixCls}-meta-detail`}>
{titleDom}
{descriptionDom}
</div> : null;
return (
<div {...others} className={classString}>
{avatarDom}
{MetaDetail}
</div>
);
};

View File

@@ -3,123 +3,71 @@
exports[`renders ./components/card/demo/basic.md correctly 1`] = `
<div
class="ant-card ant-card-bordered"
style="width:300px"
style="width:300px;"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
Card title
</div>
<div
class="ant-card-extra"
>
<a
href="#"
>
Card title
</div>
<div
class="ant-card-extra"
>
<a
href="#"
>
More
</a>
</div>
More
</a>
</div>
</div>
<div
class="ant-card-body"
>
<div>
<p>
Card content
</p>
<p>
Card content
</p>
<p>
Card content
</p>
</div>
<p>
Card content
</p>
<p>
Card content
</p>
<p>
Card content
</p>
</div>
</div>
`;
exports[`renders ./components/card/demo/border-less.md correctly 1`] = `
<div
style="background:#ECECEC;padding:30px"
style="background:#ECECEC;padding:30px;"
>
<div
class="ant-card"
style="width:300px"
style="width:300px;"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
>
Card title
</div>
Card title
</div>
</div>
<div
class="ant-card-body"
>
<div>
<p>
Card content
</p>
<p>
Card content
</p>
<p>
Card content
</p>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/card/demo/flexible-content.md correctly 1`] = `
<div
class="ant-card ant-card-bordered ant-card-hoverable"
style="width:240px"
>
<div
class="ant-card-cover"
>
<img
alt="example"
src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png"
/>
</div>
<div
class="ant-card-body"
>
<div>
<div
class="ant-card-meta"
>
<div
class="ant-card-meta-detail"
>
<div
class="ant-card-meta-title"
>
Europe Street beat
</div>
<div
class="ant-card-meta-description"
>
www.instagram.com
</div>
</div>
</div>
<p>
Card content
</p>
<p>
Card content
</p>
<p>
Card content
</p>
</div>
</div>
</div>
@@ -127,67 +75,61 @@ exports[`renders ./components/card/demo/flexible-content.md correctly 1`] = `
exports[`renders ./components/card/demo/grid-card.md correctly 1`] = `
<div
class="ant-card ant-card-bordered ant-card-contain-grid"
class="ant-card ant-card-bordered ant-card-no-hovering ant-card-contain-grid"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
>
Card Title
</div>
Card Title
</div>
</div>
<div
class="ant-card-body"
>
<div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
<div
class="ant-card-grid"
style="width:25%;text-align:center;"
>
Content
</div>
</div>
</div>
@@ -195,15 +137,15 @@ exports[`renders ./components/card/demo/grid-card.md correctly 1`] = `
exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
<div
style="background:#ECECEC;padding:30px"
style="background:#ECECEC;padding:30px;"
>
<div
class="ant-row"
style="margin-left:-8px;margin-right:-8px"
style="margin-left:-8px;margin-right:-8px;"
>
<div
class="ant-col-8"
style="padding-left:8px;padding-right:8px"
style="padding-left:8px;padding-right:8px;"
>
<div
class="ant-card"
@@ -212,27 +154,21 @@ exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
>
Card title
</div>
Card title
</div>
</div>
<div
class="ant-card-body"
>
<div>
Card content
</div>
Card content
</div>
</div>
</div>
<div
class="ant-col-8"
style="padding-left:8px;padding-right:8px"
style="padding-left:8px;padding-right:8px;"
>
<div
class="ant-card"
@@ -241,27 +177,21 @@ exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
>
Card title
</div>
Card title
</div>
</div>
<div
class="ant-card-body"
>
<div>
Card content
</div>
Card content
</div>
</div>
</div>
<div
class="ant-col-8"
style="padding-left:8px;padding-right:8px"
style="padding-left:8px;padding-right:8px;"
>
<div
class="ant-card"
@@ -270,119 +200,15 @@ exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
>
Card title
</div>
Card title
</div>
</div>
<div
class="ant-card-body"
>
<div>
Card content
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/card/demo/inner.md correctly 1`] = `
<div
class="ant-card ant-card-bordered"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
>
<div
class="ant-card-head-title"
>
Card title
</div>
</div>
</div>
<div
class="ant-card-body"
>
<div>
<p
style="font-size:14px;color:rgba(0, 0, 0, 0.85);margin-bottom:16px;font-weight:500"
>
Group title
</p>
<div
class="ant-card ant-card-bordered ant-card-type-inner"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
>
<div
class="ant-card-head-title"
>
Inner Card title
</div>
<div
class="ant-card-extra"
>
<a
href="#"
>
More
</a>
</div>
</div>
</div>
<div
class="ant-card-body"
>
<div>
Inner Card content
</div>
</div>
</div>
<div
class="ant-card ant-card-bordered ant-card-type-inner"
style="margin-top:16px"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
>
<div
class="ant-card-head-title"
>
Inner Card title
</div>
<div
class="ant-card-extra"
>
<a
href="#"
>
More
</a>
</div>
</div>
</div>
<div
class="ant-card-body"
>
<div>
Inner Card content
</div>
Card content
</div>
</div>
</div>
@@ -393,19 +219,15 @@ exports[`renders ./components/card/demo/inner.md correctly 1`] = `
exports[`renders ./components/card/demo/loading.md correctly 1`] = `
<div
class="ant-card ant-card-loading ant-card-bordered"
style="width:34%"
style="width:34%;"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
class="ant-card-head-title"
>
<div
class="ant-card-head-title"
>
Card title
</div>
Card title
</div>
</div>
<div
@@ -416,50 +238,50 @@ exports[`renders ./components/card/demo/loading.md correctly 1`] = `
>
<p
class="ant-card-loading-block"
style="width:94%"
style="width:94%;"
/>
<p>
<span
class="ant-card-loading-block"
style="width:28%"
style="width:28%;"
/>
<span
class="ant-card-loading-block"
style="width:62%"
style="width:62%;"
/>
</p>
<p>
<span
class="ant-card-loading-block"
style="width:22%"
style="width:22%;"
/>
<span
class="ant-card-loading-block"
style="width:66%"
style="width:66%;"
/>
</p>
<p>
<span
class="ant-card-loading-block"
style="width:56%"
style="width:56%;"
/>
<span
class="ant-card-loading-block"
style="width:39%"
style="width:39%;"
/>
</p>
<p>
<span
class="ant-card-loading-block"
style="width:21%"
style="width:21%;"
/>
<span
class="ant-card-loading-block"
style="width:15%"
style="width:15%;"
/>
<span
class="ant-card-loading-block"
style="width:40%"
style="width:40%;"
/>
</p>
</div>
@@ -467,336 +289,55 @@ exports[`renders ./components/card/demo/loading.md correctly 1`] = `
</div>
`;
exports[`renders ./components/card/demo/meta.md correctly 1`] = `
exports[`renders ./components/card/demo/no-padding.md correctly 1`] = `
<div
class="ant-card ant-card-bordered"
style="width:300px"
style="width:240px;"
>
<div
class="ant-card-cover"
>
<img
alt="example"
src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png"
/>
</div>
<div
class="ant-card-body"
style="padding:0;"
>
<div>
<div
class="ant-card-meta"
>
<div
class="ant-card-meta-avatar"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="ant-card-meta-detail"
>
<div
class="ant-card-meta-title"
>
Card title
</div>
<div
class="ant-card-meta-description"
>
This is the description
</div>
</div>
</div>
<div
class="custom-image"
>
<img
alt="example"
src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png"
width="100%"
/>
</div>
<div
class="custom-card"
>
<h3>
Europe Street beat
</h3>
<p>
www.instagram.com
</p>
</div>
</div>
<ul
class="ant-card-actions"
>
<li
style="width:33.333333333333336%"
>
<span>
<i
class="anticon anticon-setting"
/>
</span>
</li>
<li
style="width:33.333333333333336%"
>
<span>
<i
class="anticon anticon-edit"
/>
</span>
</li>
<li
style="width:33.333333333333336%"
>
<span>
<i
class="anticon anticon-ellipsis"
/>
</span>
</li>
</ul>
</div>
`;
exports[`renders ./components/card/demo/simple.md correctly 1`] = `
<div
class="ant-card ant-card-bordered"
style="width:300px"
style="width:300px;"
>
<div
class="ant-card-body"
>
<div>
<p>
Card content
</p>
<p>
Card content
</p>
<p>
Card content
</p>
</div>
</div>
</div>
`;
exports[`renders ./components/card/demo/tabs.md correctly 1`] = `
<div>
<div
class="ant-card ant-card-bordered ant-card-contain-tabs"
style="width:100%"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
>
<div
class="ant-card-head-title"
>
Card title
</div>
<div
class="ant-card-extra"
>
<a
href="#"
>
More
</a>
</div>
</div>
<div
class="ant-tabs ant-tabs-top ant-card-head-tabs ant-tabs-large ant-tabs-line"
>
<div
class="ant-tabs-bar"
role="tablist"
tabindex="0"
>
<div
class="ant-tabs-nav-container"
>
<span
class="ant-tabs-tab-prev ant-tabs-tab-btn-disabled"
unselectable="unselectable"
>
<span
class="ant-tabs-tab-prev-icon"
/>
</span>
<span
class="ant-tabs-tab-next ant-tabs-tab-btn-disabled"
unselectable="unselectable"
>
<span
class="ant-tabs-tab-next-icon"
/>
</span>
<div
class="ant-tabs-nav-wrap"
>
<div
class="ant-tabs-nav-scroll"
>
<div
class="ant-tabs-nav ant-tabs-nav-animated"
>
<div
class="ant-tabs-ink-bar ant-tabs-ink-bar-animated"
/>
<div
aria-disabled="false"
aria-selected="true"
class="ant-tabs-tab-active ant-tabs-tab"
role="tab"
>
tab1
</div>
<div
aria-disabled="false"
aria-selected="false"
class=" ant-tabs-tab"
role="tab"
>
tab2
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-tabs-content ant-tabs-content-animated"
style="margin-left:0%"
>
<div
aria-hidden="false"
class="ant-tabs-tabpane ant-tabs-tabpane-active"
role="tabpanel"
/>
<div
aria-hidden="true"
class="ant-tabs-tabpane ant-tabs-tabpane-inactive"
role="tabpanel"
/>
</div>
</div>
</div>
<div
class="ant-card-body"
>
<div>
<p>
content1
</p>
</div>
</div>
</div>
<br />
<br />
<div
class="ant-card ant-card-bordered ant-card-contain-tabs"
style="width:100%"
>
<div
class="ant-card-head"
>
<div
class="ant-card-head-wrapper"
/>
<div
class="ant-tabs ant-tabs-top ant-card-head-tabs ant-tabs-large ant-tabs-line"
>
<div
class="ant-tabs-bar"
role="tablist"
tabindex="0"
>
<div
class="ant-tabs-nav-container"
>
<span
class="ant-tabs-tab-prev ant-tabs-tab-btn-disabled"
unselectable="unselectable"
>
<span
class="ant-tabs-tab-prev-icon"
/>
</span>
<span
class="ant-tabs-tab-next ant-tabs-tab-btn-disabled"
unselectable="unselectable"
>
<span
class="ant-tabs-tab-next-icon"
/>
</span>
<div
class="ant-tabs-nav-wrap"
>
<div
class="ant-tabs-nav-scroll"
>
<div
class="ant-tabs-nav ant-tabs-nav-animated"
>
<div
class="ant-tabs-ink-bar ant-tabs-ink-bar-animated"
/>
<div
aria-disabled="false"
aria-selected="true"
class="ant-tabs-tab-active ant-tabs-tab"
role="tab"
>
article
</div>
<div
aria-disabled="false"
aria-selected="false"
class=" ant-tabs-tab"
role="tab"
>
app
</div>
<div
aria-disabled="false"
aria-selected="false"
class=" ant-tabs-tab"
role="tab"
>
project
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-tabs-content ant-tabs-content-animated"
style="margin-left:0%"
>
<div
aria-hidden="false"
class="ant-tabs-tabpane ant-tabs-tabpane-active"
role="tabpanel"
/>
<div
aria-hidden="true"
class="ant-tabs-tabpane ant-tabs-tabpane-inactive"
role="tabpanel"
/>
<div
aria-hidden="true"
class="ant-tabs-tabpane ant-tabs-tabpane-inactive"
role="tabpanel"
/>
</div>
</div>
</div>
<div
class="ant-card-body"
>
<div>
<p>
article content
</p>
</div>
</div>
<p>
Card content
</p>
<p>
Card content
</p>
<p>
Card content
</p>
</div>
</div>
`;

View File

@@ -14,7 +14,7 @@ describe('Card', () => {
});
function fakeResizeWindowTo(wrapper, width) {
Object.defineProperties(wrapper.instance().container, {
Object.defineProperties(wrapper.node.container, {
offsetWidth: {
get() { return width; },
configurable: true,
@@ -27,11 +27,9 @@ describe('Card', () => {
const wrapper = mount(<Card title="xxx">xxx</Card>);
fakeResizeWindowTo(wrapper, 1000);
jest.runAllTimers();
wrapper.update();
expect(wrapper.find('.ant-card-wider-padding').length).toBe(1);
expect(wrapper.hasClass('ant-card-wider-padding')).toBe(true);
fakeResizeWindowTo(wrapper, 800);
jest.runAllTimers();
wrapper.update();
expect(wrapper.find('.ant-card-wider-padding').length).toBe(0);
expect(wrapper.hasClass('ant-card-wider-padding')).toBe(false);
});
});

View File

@@ -24,9 +24,3 @@ ReactDOM.render(
</Card>
, mountNode);
````
<style>
.code-box-demo p {
margin: 0;
}
</style>

View File

@@ -1,33 +0,0 @@
---
order: 3
title:
zh-CN: 更灵活的内容展示
en-US: Customized content
---
## zh-CN
可以利用 `Card.Meta` 支持更灵活的内容。
## en-US
You can use `Card.Meta` to support more flexible content.
````jsx
import { Card } from 'antd';
const { Meta } = Card;
ReactDOM.render(
<Card
hoverable
style={{ width: 240 }}
cover={<img alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" />}
>
<Meta
title="Europe Street beat"
description="www.instagram.com"
/>
</Card>
, mountNode);
````

View File

@@ -22,7 +22,7 @@ const gridStyle = {
};
ReactDOM.render(
<Card title="Card Title">
<Card title="Card Title" noHovering>
<Card.Grid style={gridStyle}>Content</Card.Grid>
<Card.Grid style={gridStyle}>Content</Card.Grid>
<Card.Grid style={gridStyle}>Content</Card.Grid>

View File

@@ -1,48 +0,0 @@
---
order: 7
title:
zh-CN: 内部卡片
en-US: Inner card
---
## zh-CN
可以放在普通卡片内部,展示多层级结构的信息。
## en-US
It can be placed inside the ordinary card to display the information of the multilevel structure.
````jsx
import { Card } from 'antd';
ReactDOM.render(
<Card title="Card title">
<p
style={{
fontSize: 14,
color: 'rgba(0, 0, 0, 0.85)',
marginBottom: 16,
fontWeight: 500,
}}
>
Group title
</p>
<Card
type="inner"
title="Inner Card title"
extra={<a href="#">More</a>}
>
Inner Card content
</Card>
<Card
style={{ marginTop: 16 }}
type="inner"
title="Inner Card title"
extra={<a href="#">More</a>}
>
Inner Card content
</Card>
</Card>
, mountNode);
````

View File

@@ -1,33 +0,0 @@
---
order: 9
title:
zh-CN: 支持更多内容配置
en-US: Support more content configuration
---
## zh-CN
一种支持封面、头像、标题和描述信息的卡片。
## en-US
A Card that supports `cover`, `avatar`, `title` and `description`.
````jsx
import { Card, Icon, Avatar } from 'antd';
const { Meta } = Card;
ReactDOM.render(
<Card
style={{ width: 300 }}
cover={<img alt="example" src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png" />}
actions={[<Icon type="setting" />, <Icon type="edit" />, <Icon type="ellipsis" />]}
>
<Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title="Card title"
description="This is the description"
/>
</Card>
, mountNode);
````

View File

@@ -0,0 +1,43 @@
---
order: 3
title:
zh-CN: 更灵活的内容展示
en-US: Customized content
---
## zh-CN
可以调整默认边距,设定宽度。
## en-US
Customizing default width and margin.
````jsx
import { Card } from 'antd';
ReactDOM.render(
<Card style={{ width: 240 }} bodyStyle={{ padding: 0 }}>
<div className="custom-image">
<img alt="example" width="100%" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" />
</div>
<div className="custom-card">
<h3>Europe Street beat</h3>
<p>www.instagram.com</p>
</div>
</Card>
, mountNode);
````
````css
.custom-image img {
display: block;
}
.custom-card {
padding: 10px 16px;
}
.custom-card p {
color: #999;
}
````

View File

@@ -1,86 +0,0 @@
---
order: 8
title:
zh-CN: 带页签的卡片
en-US: With tabs
---
## zh-CN
可承载更多内容。
## en-US
More content can be hosted.
````jsx
import { Card } from 'antd';
const tabList = [{
key: 'tab1',
tab: 'tab1',
}, {
key: 'tab2',
tab: 'tab2',
}];
const contentList = {
tab1: <p>content1</p>,
tab2: <p>content2</p>,
};
const tabListNoTitle = [{
key: 'article',
tab: 'article',
}, {
key: 'app',
tab: 'app',
}, {
key: 'project',
tab: 'project',
}];
const contentListNoTitle = {
article: <p>article content</p>,
app: <p>app content</p>,
project: <p>project content</p>,
};
class TabsCard extends React.Component {
state = {
key: 'tab1',
noTitleKey: 'article',
}
onTabChange = (key, type) => {
console.log(key, type);
this.setState({ [type]: key });
}
render() {
return (
<div>
<Card
style={{ width: '100%' }}
title="Card title"
extra={<a href="#">More</a>}
tabList={tabList}
onTabChange={(key) => { this.onTabChange(key, 'key'); }}
>
{contentList[this.state.key]}
</Card>
<br /><br />
<Card
style={{ width: '100%' }}
tabList={tabListNoTitle}
onTabChange={(key) => { this.onTabChange(key, 'noTitleKey'); }}
>
{contentListNoTitle[this.state.noTitleKey]}
</Card>
</div>
);
}
}
ReactDOM.render(
<TabsCard />
, mountNode);
````

View File

@@ -21,17 +21,12 @@ A card can be used to display content related to a single subject. The content c
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| actions | The action list, shows at the bottom of the Card. | Array<ReactNode> | - |
| bodyStyle | Inline style to apply to the card content | object | - |
| bordered | Toggles rendering of the border around the card | boolean | `true` |
| cover | Card cover | ReactNode | - |
| extra | Content to render in the top-right corner of the card | string\|ReactNode | - |
| hoverable | Lift up when hovering card | boolean | false |
| loading | Shows a loading indicator while the contents of the card are being fetched | boolean | false |
| tabList | List of TabPane's head. | Array&lt;{key: string, tab: ReactNode}> | - |
| loading | Shows a loading indicator while the contents of the card are being fetched | boolean | `false` |
| noHovering | Whether to disable hover effect on mouse over | boolean | `false` |
| title | Card title | string\|ReactNode | - |
| type | Card style type, can be set to `inner` or not set | string | - |
| onTabChange | Callback when tab is switched | (key) => void | - |
### Card.Grid
@@ -39,13 +34,3 @@ A card can be used to display content related to a single subject. The content c
| -------- | ----------- | ---- | ------- |
| className | className of container | string | - |
| style | style object of container | object | - |
### Card.Meta
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| avatar | avatar or icon | ReactNode | - |
| className | className of container | string | - |
| description | description content | ReactNode | - |
| style | style object of container | object | - |
| title | title content | ReactNode | - |

View File

@@ -1,22 +1,8 @@
import * as React from 'react';
import React, { Component, Children } from 'react';
import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import omit from 'omit.js';
import Grid from './Grid';
import Meta from './Meta';
import Tabs from '../tabs';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
import warning from '../_util/warning';
export { CardGridProps } from './Grid';
export { CardMetaProps } from './Meta';
export type CardType = 'inner';
export interface CardTabListType {
key: string;
tab: React.ReactNode;
}
export interface CardProps {
prefixCls?: string;
@@ -27,37 +13,22 @@ export interface CardProps {
style?: React.CSSProperties;
loading?: boolean;
noHovering?: boolean;
hoverable?: boolean;
children?: React.ReactNode;
id?: string;
className?: string;
type?: CardType;
cover?: React.ReactNode;
actions?: Array<React.ReactNode>;
tabList?: CardTabListType[];
onTabChange?: (key: string) => void;
}
export default class Card extends React.Component<CardProps, {}> {
export default class Card extends Component<CardProps, {}> {
static Grid: typeof Grid = Grid;
static Meta: typeof Meta = Meta;
container: HTMLDivElement;
resizeEvent: any;
updateWiderPaddingCalled: boolean;
state = {
widerPadding: false,
};
private container: HTMLDivElement;
componentDidMount() {
this.updateWiderPadding();
this.resizeEvent = addEventListener(window, 'resize', this.updateWiderPadding);
if ('noHovering' in this.props) {
warning(
!this.props.noHovering,
'`noHovering` of Card is deperated, you can remove it safely or use `hoverable` instead.',
);
warning(!!this.props.noHovering, '`noHovering={false}` of Card is deperated, use `hoverable` instead.');
}
}
componentWillUnmount() {
if (this.resizeEvent) {
@@ -83,117 +54,73 @@ export default class Card extends React.Component<CardProps, {}> {
});
}
}
onTabChange = (key: string) => {
if (this.props.onTabChange) {
this.props.onTabChange(key);
}
}
saveRef = (node: HTMLDivElement) => {
this.container = node;
}
isContainGrid() {
let containGrid;
React.Children.forEach(this.props.children, (element: JSX.Element) => {
Children.forEach(this.props.children, (element: JSX.Element) => {
if (element && element.type && element.type === Grid) {
containGrid = true;
}
});
return containGrid;
}
getAction(actions: React.ReactNode[]) {
if (!actions || !actions.length) {
return null;
}
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;
}
render() {
const {
prefixCls = 'ant-card', className, extra, bodyStyle, noHovering, hoverable, title, loading,
bordered = true, type, cover, actions, tabList, children, ...others,
prefixCls = 'ant-card', className, extra, bodyStyle, noHovering,
title, loading, bordered = true, ...others,
} = this.props;
let children = this.props.children;
const classString = classNames(prefixCls, className, {
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-bordered`]: bordered,
[`${prefixCls}-hoverable`]: this.getCompatibleHoverable(),
[`${prefixCls}-no-hovering`]: noHovering,
[`${prefixCls}-wider-padding`]: this.state.widerPadding,
[`${prefixCls}-padding-transition`]: this.updateWiderPaddingCalled,
[`${prefixCls}-contain-grid`]: this.isContainGrid(),
[`${prefixCls}-contain-tabs`]: tabList && tabList.length,
[`${prefixCls}-type-${type}`]: !!type,
});
const loadingBlock = (
<div className={`${prefixCls}-loading-content`}>
<p className={`${prefixCls}-loading-block`} style={{ width: '94%' }} />
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '28%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '62%' }} />
</p>
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '22%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '66%' }} />
</p>
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '56%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '39%' }} />
</p>
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '21%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '15%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '40%' }} />
</p>
</div>
);
let head;
const tabs = tabList && tabList.length ? (
<Tabs className={`${prefixCls}-head-tabs`} size="large" onChange={this.onTabChange}>
{tabList.map(item => <Tabs.TabPane tab={item.tab} key={item.key} />)}
</Tabs>
) : null;
if (title || extra || tabs) {
head = (
<div className={`${prefixCls}-head`}>
<div className={`${prefixCls}-head-wrapper`}>
{title && <div className={`${prefixCls}-head-title`}>{title}</div>}
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
</div>
{tabs}
if (loading) {
children = (
<div className={`${prefixCls}-loading-content`}>
<p className={`${prefixCls}-loading-block`} style={{ width: '94%' }} />
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '28%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '62%' }} />
</p>
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '22%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '66%' }} />
</p>
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '56%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '39%' }} />
</p>
<p>
<span className={`${prefixCls}-loading-block`} style={{ width: '21%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '15%' }} />
<span className={`${prefixCls}-loading-block`} style={{ width: '40%' }} />
</p>
</div>
);
}
const coverDom = cover ? <div className={`${prefixCls}-cover`}>{cover}</div> : null;
const body = (
<div className={`${prefixCls}-body`} style={bodyStyle}>
{loading ? loadingBlock : <div>{children}</div>}
</div>
);
const actionDom = actions && actions.length ?
<ul className={`${prefixCls}-actions`}>{this.getAction(actions)}</ul> : null;
const divProps = omit(others, [
'onTabChange',
]);
let head;
if (title || extra) {
head = (
<div className={`${prefixCls}-head`}>
{title ? <div className={`${prefixCls}-head-title`}>{title}</div> : null}
{extra ? <div className={`${prefixCls}-extra`}>{extra}</div> : null}
</div>
);
}
return (
<div {...divProps} className={classString} ref={this.saveRef}>
<div {...others} className={classString} ref={this.saveRef}>
{head}
{coverDom}
{children ? body : null}
{actionDom}
<div className={`${prefixCls}-body`} style={bodyStyle}>{children}</div>
</div>
);
}

View File

@@ -22,17 +22,12 @@ cols: 1
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| actions | 卡片操作组,位置在卡片底部 | Array<ReactNode> | - |
| bodyStyle | 内容区域自定义样式 | object | - |
| bordered | 是否有边框 | boolean | true |
| cover | 卡片封面 | ReactNode | - |
| extra | 卡片右上角的操作区域 | string\|ReactNode | - |
| hoverable | 鼠标移过时可浮起 | boolean | false |
| loading | 当卡片内容还在加载中时,可以用 loading 展示一个占位 | boolean | false |
| tabList | 页签标题列表 | Array&lt;{key: string, tab: ReactNode}> | - |
| noHovering | 取消鼠标移过浮起 | boolean | false |
| title | 卡片标题 | string\|ReactNode | - |
| type | 卡片类型,可设置为 `inner` 或 不设置 | string | - |
| onTabChange | 页签切换的回调 | (key) => void | - |
### Card.Grid
@@ -40,13 +35,3 @@ cols: 1
| -------- | ----------- | ---- | ------- |
| className | 网格容器类名 | string | - |
| style | 定义网格容器类名的样式 | object | - |
### Card.Meta
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| avatar | 头像/图标 | ReactNode | - |
| className | 容器类名 | string | - |
| description | 描述内容 | ReactNode | - |
| style | 定义容器类名的样式 | object | - |
| title | 标题内容 | ReactNode | - |

View File

@@ -2,21 +2,19 @@
@import "../../style/mixins/index";
@card-prefix-cls: ~"@{ant-prefix}-card";
@card-head-height: 48px;
@card-padding-base: 24px;
@card-padding-wider: 32px;
.@{card-prefix-cls} {
.reset-component;
background: @component-background;
border-radius: @border-radius-sm;
font-size: @font-size-base;
position: relative;
transition: all .3s;
&-hoverable {
cursor: pointer;
&:hover {
box-shadow: @card-shadow;
border-color: rgba(0, 0, 0, 0.09);
}
&:not(&-no-hovering):hover {
box-shadow: @box-shadow-base;
border-color: @shadow-color;
}
&-bordered {
@@ -24,22 +22,20 @@
}
&-head {
height: @card-head-height;
line-height: @card-head-height;
background: @card-head-background;
border-bottom: @border-width-base @border-style-base @border-color-split;
padding: 0 @card-padding-base;
border-radius: @border-radius-sm @border-radius-sm 0 0;
.clearfix;
margin-bottom: -1px; // Fix card grid overflow bug: https://gw.alipayobjects.com/zos/rmsportal/XonYxBikwpgbqIQBeuhk.png
min-height: @card-head-height;
&-wrapper {
display: flex;
}
display: flex;
&-title {
font-size: @font-size-lg;
padding: @card-head-padding 0;
text-overflow: ellipsis;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
color: @card-head-color;
@@ -47,20 +43,10 @@
display: inline-block;
flex: 1;
}
.@{ant-prefix}-tabs {
margin-bottom: -17px;
clear: both;
&-bar {
border-bottom: @border-width-base @border-style-base @border-color-split;
}
}
}
&-extra {
float: right;
padding: @card-head-padding + 1.5px 0;
text-align: right;
// https://stackoverflow.com/a/22429853/3040605
margin-left: auto;
@@ -91,66 +77,6 @@
}
}
&-contain-tabs &-head-title {
padding-bottom: 0;
min-height: @card-head-height - @card-head-padding;
}
&-contain-tabs &-extra {
padding-bottom: 0;
}
&-cover > * {
width: 100%;
display: block;
}
&-actions {
border-top: @border-width-base @border-style-base @border-color-split;
background: @card-actions-background;
.clearfix;
list-style: none;
margin: 0;
padding: 0;
& > li {
float: left;
text-align: center;
margin: 12px 0;
color: @text-color-secondary;
& > span {
display: inline-block;
font-size: 14px;
cursor: pointer;
line-height: 22px;
min-width: 32px;
position: relative;
&:hover {
color: @primary-color;
transition: color .3s;
}
& > .anticon {
font-size: 16px;
}
a {
color: @text-color-secondary;
&:hover {
color: @primary-color;
}
}
}
&:not(:last-child) {
border-right: @border-width-base @border-style-base @border-color-split;
}
}
}
&-wider-padding &-head {
padding: 0 @card-padding-wider;
}
@@ -159,6 +85,10 @@
padding: @card-padding-base @card-padding-wider;
}
&-wider-padding &-extra {
right: @card-padding-wider;
}
&-padding-transition &-head,
&-padding-transition &-body {
transition: padding .3s;
@@ -168,54 +98,6 @@
transition: right .3s;
}
&-type-inner &-head {
padding: 0 @card-padding-base;
background: @background-color-light;
&-title {
padding: @card-inner-head-padding 0;
font-size: @font-size-base;
}
}
&-type-inner &-body {
padding: 16px @card-padding-base;
}
&-type-inner &-extra {
padding: @card-inner-head-padding + 1.5px 0;
}
&-meta {
margin: -4px 0;
.clearfix;
&-avatar {
padding-right: 16px;
float: left;
}
&-detail {
overflow: hidden;
> div:not(:last-child) {
margin-bottom: 8px;
}
}
&-title {
font-size: @font-size-lg;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: @card-head-color;
font-weight: 500;
}
&-description {
color: @text-color-secondary;
}
}
&-loading &-body {
user-select: none;
padding: 0;
@@ -223,14 +105,11 @@
&-loading-content {
padding: @card-padding-base;
p {
margin: 0;
}
}
&-loading-block {
display: inline-block;
margin: 5px 2% 0 0;
margin: 5px 1% 0;
height: 14px;
border-radius: @border-radius-sm;
background: linear-gradient(90deg, rgba(207, 216, 220, .2), rgba(207, 216, 220, .4), rgba(207, 216, 220, .2));

View File

@@ -1,5 +1,2 @@
import '../../style/index.less';
import './index.less';
// style dependencies
import '../../tabs/style';

View File

@@ -24,7 +24,7 @@ exports[`renders ./components/carousel/demo/autoplay.md correctly 1`] = `
<div
class="slick-slide slick-active slick-cloned"
data-index="0"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -34,7 +34,7 @@ exports[`renders ./components/carousel/demo/autoplay.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="1"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -44,7 +44,7 @@ exports[`renders ./components/carousel/demo/autoplay.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="2"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -54,7 +54,7 @@ exports[`renders ./components/carousel/demo/autoplay.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="3"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -99,7 +99,7 @@ exports[`renders ./components/carousel/demo/basic.md correctly 1`] = `
<div
class="slick-slide slick-active slick-cloned"
data-index="0"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -109,7 +109,7 @@ exports[`renders ./components/carousel/demo/basic.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="1"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -119,7 +119,7 @@ exports[`renders ./components/carousel/demo/basic.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="2"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -129,7 +129,7 @@ exports[`renders ./components/carousel/demo/basic.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="3"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -166,7 +166,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
<div
class="slick-slide slick-active slick-cloned"
data-index="0"
style="outline:none;position:relative;left:0;opacity:1;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease"
style="outline:none;position:relative;left:0;opacity:1;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease;"
tabindex="-1"
>
<h3>
@@ -176,7 +176,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="1"
style="outline:none;position:relative;left:0;opacity:0;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease"
style="outline:none;position:relative;left:0;opacity:0;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease;"
tabindex="-1"
>
<h3>
@@ -186,7 +186,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="2"
style="outline:none;position:relative;left:0;opacity:0;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease"
style="outline:none;position:relative;left:0;opacity:0;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease;"
tabindex="-1"
>
<h3>
@@ -196,7 +196,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="3"
style="outline:none;position:relative;left:0;opacity:0;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease"
style="outline:none;position:relative;left:0;opacity:0;transition:opacity 500ms ease;-webkit-transition:opacity 500ms ease;"
tabindex="-1"
>
<h3>
@@ -233,7 +233,7 @@ exports[`renders ./components/carousel/demo/vertical.md correctly 1`] = `
<div
class="slick-slide slick-active slick-cloned"
data-index="0"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -243,7 +243,7 @@ exports[`renders ./components/carousel/demo/vertical.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="1"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -253,7 +253,7 @@ exports[`renders ./components/carousel/demo/vertical.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="2"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>
@@ -263,7 +263,7 @@ exports[`renders ./components/carousel/demo/vertical.md correctly 1`] = `
<div
class="slick-slide slick-cloned"
data-index="3"
style="outline:none"
style="outline:none;"
tabindex="-1"
>
<h3>

View File

@@ -5,8 +5,8 @@ import Carousel from '..';
describe('Carousel', () => {
it('should has innerSlider', () => {
const wrapper = mount(<Carousel><div /></Carousel>);
const { innerSlider } = wrapper.instance();
const innerSliderFromRefs = wrapper.instance().slick.innerSlider;
const { innerSlider } = wrapper.node;
const innerSliderFromRefs = wrapper.node.refs.slick.innerSlider;
expect(innerSlider).toBe(innerSliderFromRefs);
expect(typeof innerSlider.slickNext).toBe('function');
});

View File

@@ -24,12 +24,4 @@ A carousel component. Scales with its container.
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` |
| vertical | Whether to use a vertical display | boolean | `false` |
## Methods
| Name | Description |
| ---- | ----------- |
| goTo(slideNumber) | Change current slide to given slide number |
| next() | Change current slide to next slide |
| prev() | Change current slide to previous slide |
For more info on the parameters, refer to the <https://github.com/akiran/react-slick>

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import debounce from 'lodash.debounce';
// matchMedia polyfill for
@@ -66,7 +66,7 @@ export interface CarouselProps {
slickGoTo?: number;
}
export default class Carousel extends React.Component<CarouselProps, {}> {
export default class Carousel extends React.Component<CarouselProps, any> {
static defaultProps = {
dots: true,
arrows: false,
@@ -74,11 +74,13 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
draggable: false,
};
refs: {
slick: any,
};
innerSlider: any;
private slick: any;
constructor(props: CarouselProps) {
constructor(props) {
super(props);
this.onWindowResized = debounce(this.onWindowResized, 500, {
leading: false,
@@ -90,8 +92,9 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
if (autoplay) {
window.addEventListener('resize', this.onWindowResized);
}
const { slick } = this.refs;
// https://github.com/ant-design/ant-design/issues/7191
this.innerSlider = this.slick && this.slick.innerSlider;
this.innerSlider = slick && slick.innerSlider;
}
componentWillUnmount() {
@@ -104,28 +107,13 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
onWindowResized = () => {
// Fix https://github.com/ant-design/ant-design/issues/2550
const { slick } = this.refs;
const { autoplay } = this.props;
if (autoplay && this.slick && this.slick.innerSlider && this.slick.innerSlider.autoPlay) {
this.slick.innerSlider.autoPlay();
if (autoplay && slick && slick.innerSlider && slick.innerSlider.autoPlay) {
slick.innerSlider.autoPlay();
}
}
saveSlick = (node: any) => {
this.slick = node;
}
next() {
this.slick.slickNext();
}
prev() {
this.slick.slickPrev();
}
goTo(slide: number) {
this.slick.slickGoTo(slide);
}
render() {
let props = {
...this.props,
@@ -142,7 +130,7 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
return (
<div className={className}>
<SlickCarousel ref={this.saveSlick} {...props} />
<SlickCarousel ref="slick" {...props} />
</div>
);
}

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