mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-18 07:12:28 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97d3422043 | ||
|
|
a609518d28 | ||
|
|
ef6d7a5d90 | ||
|
|
5be1bad67f | ||
|
|
b70fede5de | ||
|
|
358aa84fef | ||
|
|
6f716d1003 | ||
|
|
739c6ead54 | ||
|
|
a7255ee885 | ||
|
|
06ff0d44db | ||
|
|
e96b0fc768 | ||
|
|
8489fedb4c | ||
|
|
adf98d3c19 | ||
|
|
ba87b45903 | ||
|
|
1e8830637f | ||
|
|
2275195e15 | ||
|
|
dcf9d4c294 |
10
.babelrc
Normal file
10
.babelrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": ["es2015", "react", "stage-0"],
|
||||
"plugins": [
|
||||
"add-module-exports"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
version: 2
|
||||
|
||||
references:
|
||||
container_config: &container_config
|
||||
docker:
|
||||
- image: circleci/node:8
|
||||
working_directory: ~/ant-design
|
||||
|
||||
attach_workspace: &attach_workspace
|
||||
attach_workspace:
|
||||
at: ~/ant-design
|
||||
|
||||
install_react: &install_react
|
||||
run: REACT=15 ./scripts/install-react.sh
|
||||
|
||||
react_15: &react_15
|
||||
environment:
|
||||
REACT: 15
|
||||
|
||||
react_16: &react_16
|
||||
environment:
|
||||
REACT: 16
|
||||
|
||||
workflow: &workflow
|
||||
jobs:
|
||||
- setup:
|
||||
filters:
|
||||
branches:
|
||||
ignore: gh-pages
|
||||
- dist:
|
||||
requires:
|
||||
- setup
|
||||
- compile:
|
||||
requires:
|
||||
- setup
|
||||
- lint:
|
||||
requires:
|
||||
- setup
|
||||
- test_dist:
|
||||
requires:
|
||||
- dist
|
||||
- test_lib:
|
||||
requires:
|
||||
- compile
|
||||
- test_es:
|
||||
requires:
|
||||
- compile
|
||||
- test_dom:
|
||||
requires:
|
||||
- setup
|
||||
- test_node:
|
||||
requires:
|
||||
- setup
|
||||
- test_dist_15:
|
||||
requires:
|
||||
- dist
|
||||
- test_lib_15:
|
||||
requires:
|
||||
- compile
|
||||
- test_es_15:
|
||||
requires:
|
||||
- compile
|
||||
- test_dom_15:
|
||||
requires:
|
||||
- setup
|
||||
- test_node_15:
|
||||
requires:
|
||||
- setup
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
<<: *container_config
|
||||
steps:
|
||||
- checkout
|
||||
- run: node -v
|
||||
- run: npm -v
|
||||
- run: npm install
|
||||
- run:
|
||||
command: |
|
||||
set +eo
|
||||
npm ls
|
||||
true
|
||||
- persist_to_workspace:
|
||||
root: ~/ant-design
|
||||
paths:
|
||||
- node_modules
|
||||
- store_artifacts:
|
||||
path: package-lock.json
|
||||
|
||||
dist:
|
||||
<<: *container_config
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run: npm run dist
|
||||
- run: node ./tests/dekko/dist.test.js
|
||||
- persist_to_workspace:
|
||||
root: ~/ant-design
|
||||
paths:
|
||||
- dist
|
||||
|
||||
compile:
|
||||
<<: *container_config
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run: npm run compile
|
||||
- run: node ./tests/dekko/lib.test.js
|
||||
- persist_to_workspace:
|
||||
root: ~/ant-design
|
||||
paths:
|
||||
- lib
|
||||
- es
|
||||
|
||||
lint:
|
||||
<<: *container_config
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run: npm run lint
|
||||
|
||||
test_dist:
|
||||
<<: *container_config
|
||||
<<: *react_16
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run:
|
||||
command: npm test -- -w 1
|
||||
environment:
|
||||
LIB_DIR: dist
|
||||
|
||||
test_lib:
|
||||
<<: *container_config
|
||||
<<: *react_16
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run:
|
||||
command: npm test -- -w 1
|
||||
environment:
|
||||
LIB_DIR: lib
|
||||
|
||||
test_es:
|
||||
<<: *container_config
|
||||
<<: *react_16
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run:
|
||||
command: npm test -- -w 1
|
||||
environment:
|
||||
LIB_DIR: es
|
||||
|
||||
test_dom:
|
||||
<<: *container_config
|
||||
<<: *react_16
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run: npm test -- -w 1 --coverage
|
||||
- run: bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
test_node:
|
||||
<<: *container_config
|
||||
<<: *react_16
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run: npm run test-node -- -w 1
|
||||
|
||||
test_dist_15:
|
||||
<<: *container_config
|
||||
<<: *react_15
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- *install_react
|
||||
- run:
|
||||
command: npm test -- -w 1 -u
|
||||
environment:
|
||||
LIB_DIR: dist
|
||||
|
||||
test_lib_15:
|
||||
<<: *container_config
|
||||
<<: *react_15
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- *install_react
|
||||
- run:
|
||||
command: npm test -- -w 1 -u
|
||||
environment:
|
||||
LIB_DIR: lib
|
||||
|
||||
test_es_15:
|
||||
<<: *container_config
|
||||
<<: *react_15
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- *install_react
|
||||
- run:
|
||||
command: npm test -- -w 1 -u
|
||||
environment:
|
||||
LIB_DIR: es
|
||||
|
||||
test_dom_15:
|
||||
<<: *container_config
|
||||
<<: *react_15
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- *install_react
|
||||
- run: npm test -- -w 1 -u
|
||||
|
||||
test_node_15:
|
||||
<<: *container_config
|
||||
<<: *react_15
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- *install_react
|
||||
- run: npm run test-node -- -w 1 -u
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_test:
|
||||
<<: *workflow
|
||||
nightly:
|
||||
<<: *workflow
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
@@ -1,9 +1,2 @@
|
||||
codecov:
|
||||
branch: master
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
# Fail the status if coverage drops by >= 0.1%
|
||||
threshold: 0.1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 🎨 editorconfig.org
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
components/**/*.js
|
||||
components/**/*.jsx
|
||||
components/*/__tests__/type.tsx
|
||||
!.eslintrc.js
|
||||
!components/*/__tests__/**/*.js
|
||||
!components/*/demo/*
|
||||
!.*.js
|
||||
# Docs templates
|
||||
site/theme/template/IconDisplay/*.js
|
||||
site/theme/template/IconDisplay/*.jsx
|
||||
|
||||
61
.eslintrc.js
61
.eslintrc.js
@@ -1,5 +1,5 @@
|
||||
const eslintrc = {
|
||||
extends: ['airbnb', 'prettier'],
|
||||
extends: ['eslint-config-airbnb'],
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
@@ -8,33 +8,44 @@ const eslintrc = {
|
||||
es6: true,
|
||||
},
|
||||
parser: 'babel-eslint',
|
||||
plugins: ['markdown', 'react', 'babel'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
experimentalObjectRestSpread: true,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
'markdown',
|
||||
'react',
|
||||
'babel',
|
||||
],
|
||||
rules: {
|
||||
'react/jsx-one-expression-per-line': 0,
|
||||
'func-names': 0,
|
||||
'arrow-body-style': 0,
|
||||
'react/sort-comp': 0,
|
||||
'react/prop-types': 0,
|
||||
'react/forbid-prop-types': 0,
|
||||
'react/jsx-indent': 0,
|
||||
'react/jsx-wrap-multilines': ['error', { declaration: false, assignment: false }],
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: [
|
||||
'site/**',
|
||||
'tests/**',
|
||||
'scripts/**',
|
||||
'**/*.test.js',
|
||||
'**/__tests__/*',
|
||||
'*.config.js',
|
||||
'**/*.md',
|
||||
],
|
||||
},
|
||||
],
|
||||
'react/jsx-first-prop-new-line': 0,
|
||||
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.md'] }],
|
||||
'import/extensions': 0,
|
||||
'import/no-unresolved': 0,
|
||||
'import/no-extraneous-dependencies': 0,
|
||||
'prefer-destructuring': 0,
|
||||
'no-param-reassign': 0,
|
||||
'no-return-assign': 0,
|
||||
'max-len': 0,
|
||||
'consistent-return': 0,
|
||||
'no-redeclare': 0,
|
||||
'react/require-extension': 0,
|
||||
'jsx-a11y/no-static-element-interactions': 0,
|
||||
'jsx-a11y/anchor-has-content': 0,
|
||||
'jsx-a11y/click-events-have-key-events': 0,
|
||||
'jsx-a11y/anchor-is-valid': 0,
|
||||
'react/no-danger': 0,
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'function-paren-newline': 0,
|
||||
'object-curly-newline': 0,
|
||||
'no-restricted-globals': 0,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -50,18 +61,10 @@ if (process.env.RUN_ENV === 'DEMO') {
|
||||
'no-console': 0,
|
||||
'no-plusplus': 0,
|
||||
'eol-last': 0,
|
||||
'no-script-url': 0,
|
||||
'prefer-rest-params': 0,
|
||||
'react/no-access-state-in-setstate': 0,
|
||||
'react/destructuring-assignment': 0,
|
||||
'react/no-multi-comp': 0,
|
||||
'jsx-a11y/href-no-hash': 0,
|
||||
'prefer-destructuring': 0, // TODO: remove later
|
||||
'max-len': 0, // TODO: remove later
|
||||
'consistent-return': 0, // TODO: remove later
|
||||
'no-return-assign': 0, // TODO: remove later
|
||||
'no-param-reassign': 0, // TODO: remove later
|
||||
'import/no-extraneous-dependencies': 0,
|
||||
'import/newline-after-import': 0,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
57
.github/CONTRIBUTING.md
vendored
57
.github/CONTRIBUTING.md
vendored
@@ -1,13 +1,58 @@
|
||||
# Contributing to Ant Design
|
||||
|
||||
Want to contribute to Ant Design? There are a few things you need to know.
|
||||
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.
|
||||
|
||||
We wrote a **[contribution guide](https://ant.design/docs/react/contributing)** to help you get started.
|
||||
Anyway, these are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
|
||||
|
||||
---
|
||||
|
||||
# 参与共建
|
||||
## Do your homework before asking a question
|
||||
|
||||
想要给 Ant Design 贡献自己的一份力量?
|
||||
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.
|
||||
|
||||
我们写了一份 **[贡献指南](https://ant.design/docs/react/contributing-cn)** 来帮助你开始。
|
||||
The following guidelines are about *How to avoid Homework Questions*.
|
||||
|
||||
### 1. Read the documentation.
|
||||
|
||||
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.
|
||||
|
||||
Tips: choose the corresponding documentation with versions selector which in the bottom-right corner.
|
||||
|
||||
### 2. Make sure that your question is about Ant Design, not React
|
||||
|
||||
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.
|
||||
|
||||
### 3. Read the FAQ and search the issues list of Ant Design
|
||||
|
||||
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.
|
||||
|
||||
P.S.
|
||||
|
||||
1. [FAQ](https://github.com/ant-design/ant-design/wiki/FAQ)
|
||||
1. [Issues list](https://github.com/ant-design/ant-design/issues)
|
||||
|
||||
## Close your issue if it's solved
|
||||
|
||||
It is a good habit which will save maintainers' time. Thank you!
|
||||
|
||||
## Providing a demo while reporting a bug
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Tips about Feature Request
|
||||
|
||||
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:
|
||||
|
||||
1. Request or operate data
|
||||
|
||||
|
||||
## Tips about Pull Request
|
||||
|
||||
**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)
|
||||
|
||||
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.
|
||||
|
||||
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
⚠️ ⚠️ ⚠️ IMPORTANT: Please use the following link to create a new issue: ⚠️ ⚠️ ⚠️
|
||||
IMPORTANT: Please use the following link to create a new issue:
|
||||
|
||||
http://new-issue.ant.design
|
||||
|
||||
@@ -7,7 +7,7 @@ If your issue was not created using the app above, it will be closed immediately
|
||||
-->
|
||||
|
||||
<!--
|
||||
⚠️ ⚠️ ⚠️ 注意:请使用下面的链接来新建 issue: ⚠️ ⚠️ ⚠️
|
||||
注意:请使用下面的链接来新建 issue:
|
||||
|
||||
http://new-issue.ant.design
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
name: "⚠️ Please use new-issue.ant.design ⚠️"
|
||||
about: The issue which is not created via http://new-issue.ant.design will be closed
|
||||
immediately.
|
||||
labels:
|
||||
|
||||
---
|
||||
|
||||
The issue which is not created via http://new-issue.ant.design will be closed immediately.
|
||||
|
||||
---
|
||||
|
||||
注意:不是用 http://new-issue.ant.design 创建的 issue 会被立即关闭。
|
||||
61
.github/PULL_REQUEST_TEMPLATE.md
vendored
61
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,53 +1,22 @@
|
||||
First of all, thank you for your contribution! 😄
|
||||
First of all, thank you for your contribution! :-)
|
||||
|
||||
New feature please send pull request to feature branch, and rest to master branch.
|
||||
Pull request will be merged after one of collaborators approve.
|
||||
Please makes sure that these form are filled before submitting your pull request, thank you!
|
||||
Please makes sure that these checkboxes are checked before submitting your PR, thank you!
|
||||
|
||||
[[中文版模板 / Chinese template](https://github.com/ant-design/ant-design/blob/master/.github/PULL_REQUEST_TEMPLATE/pr_cn.md)]
|
||||
* [ ] Make sure that you propose PR to right branch: bugfix for `master`, feature for latest active branch `feature-x.x`.
|
||||
* [ ] Make sure that you follow antd's [code convention](https://github.com/ant-design/ant-design/wiki/Code-convention-for-antd).
|
||||
* [ ] Run `npm run lint` and fix those errors before submitting in order to keep consistent code style.
|
||||
* [ ] Rebase before creating a PR to keep commit history clear.
|
||||
* [ ] Add some descriptions and refer relative issues for you PR.
|
||||
|
||||
### This is a ...
|
||||
Extra checklist:
|
||||
|
||||
- [ ] New feature
|
||||
- [ ] Bug fix
|
||||
- [ ] Site / document update
|
||||
- [ ] Component style update
|
||||
- [ ] TypeScript definition update
|
||||
- [ ] Refactoring
|
||||
- [ ] Code style optimization
|
||||
- [ ] Branch merge
|
||||
- [ ] Other (about what?)
|
||||
**if** *isBugFix* **:**
|
||||
|
||||
### What's the background?
|
||||
* [ ] Make sure that you add at least one unit test for the bug which you had fixed.
|
||||
|
||||
> 1. Describe the source of requirement.
|
||||
> 2. Resolve what problem.
|
||||
> 3. Related issue link.
|
||||
**elif** *isNewFeature* **:**
|
||||
|
||||
### API Realization (Optional if not new feature)
|
||||
|
||||
> 1. Basic thought of solution and other optional proposal.
|
||||
> 2. List final API realization and usage sample.
|
||||
> 3. GIF or snapshot should be provided if includes UI/interactive modification.
|
||||
|
||||
### What's the effect? (Optional if not new feature)
|
||||
|
||||
> 1. Does this PR affect user? Which part will be affected?
|
||||
> 2. What will say in changelog?
|
||||
> 3. Does this PR contains potential break change or other risk?
|
||||
|
||||
### Changelog description (Optional if not new feature)
|
||||
|
||||
> 1. English description
|
||||
> 2. Chinese description (optional)
|
||||
|
||||
### Self Check before Merge
|
||||
|
||||
- [ ] Doc is updated/provided or not needed
|
||||
- [ ] Demo is updated/provided or not needed
|
||||
- [ ] TypeScript definition is updated/provided or not needed
|
||||
- [ ] Changelog is provided or not needed
|
||||
|
||||
### Additional Plan? (Optional if not new feature)
|
||||
|
||||
> If this PR related with other PR or following info. You can type here.
|
||||
* [ ] Update API docs for the component.
|
||||
* [ ] Update/Add demo to demonstrate new feature.
|
||||
* [ ] Update TypeScript definition for the component.
|
||||
* [ ] Add unit tests for the feature.
|
||||
|
||||
52
.github/PULL_REQUEST_TEMPLATE/pr_cn.md
vendored
52
.github/PULL_REQUEST_TEMPLATE/pr_cn.md
vendored
@@ -1,52 +0,0 @@
|
||||
首先,感谢你的贡献! 😄
|
||||
|
||||
新特性请提交至 feature 分支,其余可提交至 master 分支。
|
||||
在一个维护者审核通过后合并。
|
||||
请确保填写以下 pull request 的信息,谢谢!~
|
||||
|
||||
[[English Template / 英文模板](?expand=1)]
|
||||
|
||||
### 这个变动的性质是
|
||||
|
||||
- [ ] 新特性提交
|
||||
- [ ] 日常 bug 修复
|
||||
- [ ] 站点、文档改进
|
||||
- [ ] 组件样式改进
|
||||
- [ ] TypeScript 定义更新
|
||||
- [ ] 重构
|
||||
- [ ] 代码风格优化
|
||||
- [ ] 分支合并
|
||||
- [ ] 其他改动(是关于什么的改动?)
|
||||
|
||||
### 需求背景
|
||||
|
||||
> 1. 描述相关需求的来源。
|
||||
> 2. 要解决的问题。
|
||||
> 3. 相关的 issue 讨论链接。
|
||||
|
||||
### 实现方案和 API(非新功能可选)
|
||||
|
||||
> 1. 基本的解决思路和其他可选方案。
|
||||
> 2. 列出最终的 API 实现和用法。
|
||||
> 3. 涉及UI/交互变动需要有截图或 GIF。
|
||||
|
||||
### 对用户的影响和可能的风险(非新功能可选)
|
||||
|
||||
> 1. 这个改动对用户端是否有影响?影响的方面有哪些?
|
||||
> 2. 是否有可能隐含的 break change 和其他风险?
|
||||
|
||||
### Changelog 描述(非新功能可选)
|
||||
|
||||
> 1. 英文描述
|
||||
> 2. 中文描述(可选)
|
||||
|
||||
### 请求合并前的自查清单
|
||||
|
||||
- [ ] 文档已补充或无须补充
|
||||
- [ ] 代码演示已提供或无须提供
|
||||
- [ ] TypeScript 定义已补充或无须补充
|
||||
- [ ] Changelog 已提供或无须提供
|
||||
|
||||
### 后续计划(非新功能可选)
|
||||
|
||||
> 如果这个提交后面还有相关的其他提交和跟进信息,可以写在这里。
|
||||
14
.github/lock.yml
vendored
14
.github/lock.yml
vendored
@@ -1,14 +0,0 @@
|
||||
# Configuration for lock-threads - https://github.com/dessant/lock-threads
|
||||
|
||||
# Number of days of inactivity before a closed issue or pull request is locked
|
||||
daysUntilLock: 365
|
||||
# Comment to post before locking. Set to `false` to disable
|
||||
lockComment: >
|
||||
This thread has been automatically locked because it has not had recent
|
||||
activity. Please open a new issue for related bugs and link to relevant
|
||||
comments in this thread.
|
||||
# Issues or pull requests with these labels will not be locked
|
||||
# exemptLabels:
|
||||
# - no-locking
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -38,8 +38,3 @@ components/**/*.jsx
|
||||
!components/**/__tests__/*.js
|
||||
!components/**/__tests__/*.js.snap
|
||||
/.history
|
||||
# Docs templates
|
||||
site/theme/template/IconDisplay/*.js
|
||||
site/theme/template/IconDisplay/*.jsx
|
||||
site/theme/template/IconDisplay/fields.js
|
||||
*.tmp
|
||||
|
||||
40
.jest.js
40
.jest.js
@@ -2,36 +2,44 @@ const libDir = process.env.LIB_DIR;
|
||||
|
||||
const transformIgnorePatterns = [
|
||||
'/dist/',
|
||||
'node_modules/[^/]+?/(?!(es|node_modules)/)', // Ignore modules without es dir
|
||||
'node_modules\/[^/]+?\/(?!(es|node_modules)\/)', // Ignore modules without es dir
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
setupFiles: ['./tests/setup.js'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'],
|
||||
modulePathIgnorePatterns: ['/_site/'],
|
||||
testPathIgnorePatterns: ['/node_modules/', 'dekko', 'node'],
|
||||
setupFiles: [
|
||||
'./tests/setup.js',
|
||||
],
|
||||
moduleFileExtensions: [
|
||||
'ts',
|
||||
'tsx',
|
||||
'js',
|
||||
'jsx',
|
||||
'json',
|
||||
'md',
|
||||
],
|
||||
modulePathIgnorePatterns: [
|
||||
'/_site/',
|
||||
],
|
||||
testPathIgnorePatterns: [
|
||||
'/node_modules/',
|
||||
'dekko',
|
||||
'node',
|
||||
],
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
'\\.md$': './node_modules/antd-tools/lib/jest/demoPreprocessor',
|
||||
'\\.(jpg|png|gif|svg)$': './node_modules/antd-tools/lib/jest/imagePreprocessor',
|
||||
},
|
||||
testRegex: `${libDir === 'dist' ? 'demo' : '.*'}\\.test\\.js$`,
|
||||
testRegex: libDir === 'dist' ? 'demo\\.test\\.js$' : '.*\\.test\\.js$',
|
||||
collectCoverageFrom: [
|
||||
'components/**/*.{ts,tsx}',
|
||||
'!components/*/style/index.tsx',
|
||||
'!components/style/index.tsx',
|
||||
'!components/*/locale/index.tsx',
|
||||
'!components/*/__tests__/**/type.tsx',
|
||||
'!components/**/*/interface.{ts,tsx}',
|
||||
],
|
||||
transformIgnorePatterns,
|
||||
snapshotSerializers: ['enzyme-to-json/serializer'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfig: './tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
testURL: 'http://localhost',
|
||||
snapshotSerializers: [
|
||||
'enzyme-to-json/serializer',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
// jest config for server render environment
|
||||
module.exports = {
|
||||
setupFiles: ['./tests/setup.js'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
|
||||
setupFiles: [
|
||||
'./tests/setup.js',
|
||||
],
|
||||
moduleFileExtensions: [
|
||||
'ts',
|
||||
'tsx',
|
||||
'js',
|
||||
'md',
|
||||
],
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
'\\.md$': './node_modules/antd-tools/lib/jest/demoPreprocessor',
|
||||
'\\.(jpg|png|gif|svg)$': './node_modules/antd-tools/lib/jest/imagePreprocessor',
|
||||
},
|
||||
testRegex: 'demo\\.test\\.js$',
|
||||
testEnvironment: 'node',
|
||||
snapshotSerializers: ['enzyme-to-json/serializer'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfigFile: './tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
snapshotSerializers: [
|
||||
'enzyme-to-json/serializer'
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
**/*.md
|
||||
**/*.svg
|
||||
**/*.ejs
|
||||
**/*.html
|
||||
package.json
|
||||
.umi
|
||||
.umi-production
|
||||
19
.prettierrc
19
.prettierrc
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"overrides": [
|
||||
{
|
||||
"files": ".prettierrc",
|
||||
"options": {
|
||||
"parser": "json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ".stylelintrc",
|
||||
"options": {
|
||||
"parser": "json"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
const config = {
|
||||
plugins: [
|
||||
'remark-preset-lint-recommended',
|
||||
['remark-lint-list-item-indent', 'space'],
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,4 +0,0 @@
|
||||
components/style/color/bezierEasing.less
|
||||
components/style/color/colorPalette.less
|
||||
components/style/color/tinyColor.less
|
||||
components/style/core/base.less
|
||||
16
.stylelintrc
16
.stylelintrc
@@ -1,11 +1,21 @@
|
||||
{
|
||||
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
|
||||
"extends": "stylelint-config-standard",
|
||||
"rules": {
|
||||
"comment-empty-line-before": null,
|
||||
"declaration-empty-line-before": null,
|
||||
"function-comma-newline-after": null,
|
||||
"function-name-case": null,
|
||||
"function-parentheses-newline-inside": null,
|
||||
"function-max-empty-lines": null,
|
||||
"function-whitespace-after": null,
|
||||
"indentation": null,
|
||||
"number-leading-zero": null,
|
||||
"number-no-trailing-zeros": null,
|
||||
"rule-empty-line-before": null,
|
||||
"selector-combinator-space-after": null,
|
||||
"selector-list-comma-newline-after": null,
|
||||
"selector-pseudo-element-colon-notation": null,
|
||||
"no-invalid-double-slash-comments": null,
|
||||
"no-descending-specificity": null
|
||||
"unit-no-unknown": null,
|
||||
"value-list-max-empty-lines": null
|
||||
}
|
||||
}
|
||||
|
||||
52
.travis.yml
52
.travis.yml
@@ -3,29 +3,35 @@ sudo: false
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- 11
|
||||
- 8
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.npm
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
408
AUTHORS.txt
408
AUTHORS.txt
@@ -1,431 +1,175 @@
|
||||
17073025 <17073025@cnsuning.com>
|
||||
282159468 <282159468@qq.com>
|
||||
778758944 <778758944@qq.com>
|
||||
Aaron Planell López <aaronplanell@gmail.com>
|
||||
Aashutosh Rathi <aashutoshrathi@gmail.com>
|
||||
Aditya Padhi <aditya.padhi@outlook.com>
|
||||
Adrian Dimitrov <dimitrov.adrian@gmail.com>
|
||||
Alan Braithwaite <asbraithwaite@gmail.com>
|
||||
Albert Zheng <lisong.zheng@gmail.com>
|
||||
Albert 理斯特 <shuaizhexu@gmail.com>
|
||||
Aleck Landgraf <aleck.landgraf@gmail.com>
|
||||
Alexander <labriko@yandex.ru>
|
||||
Alexander Anpleenko <vaeum@yandex.com>
|
||||
Alexander Suevalov <suevalov.work@gmail.com>
|
||||
Alexandre Kirszenberg <a.kirszenberg@gmail.com>
|
||||
Alexey Yakovlev <yallie@yandex.ru>
|
||||
Alireza <alireza.mh@gmail.com>
|
||||
Amorites <751809522@qq.com>
|
||||
Amumu <yoyo837@hotmail.com>
|
||||
Anas Tawfeek <anas.tawfeek@outlook.com>
|
||||
Andre Perunicic <andre@intoli.com>
|
||||
Andrew Murray <radarhere@gmail.com>
|
||||
Andrey G <plandem@gmail.com>
|
||||
Andrzej Dybionka <andrzej@arabel.la>
|
||||
André <mazoni.andre@gmail.com>
|
||||
Arnab Sen <arnabsen@gmail.com>
|
||||
Arthur Denner Oliveira Santos <arthurdenner7@gmail.com>
|
||||
Arvin Xu <arvinx@foxmail.com>
|
||||
Ash Kumar <kumar.ashwin@outlook.com>
|
||||
BK Heleth <bon.hoo@hotmail.com>
|
||||
Babajide Fowotade <jide.b.tade@gmail.com>
|
||||
Bartek <bartek.kozera@gmail.com>
|
||||
Benedikt Franke <benedikt@franke.tech>
|
||||
Benjamin Kniffler <bkniffler@me.com>
|
||||
Benjy Cui <benjytrys@gmail.com>
|
||||
Benoît Latinier <benoit@latinier.fr>
|
||||
Bernie <bernie.wangbj@gmail.com>
|
||||
Bilal Sirazitdinov <bilalsir@yandex.ru>
|
||||
Bill Sheikh <bilawals22@gmail.com>
|
||||
Bo Chen <bochen2014@yahoo.com>
|
||||
Bozhao <yubz86@gmail.com>
|
||||
Bradley Xu <xgheaven@gmail.com>
|
||||
Brett Lamy <bel423@me.com>
|
||||
Brook Shi <iwxiaot@gmail.com>
|
||||
Bruce Mitchener <bruce.mitchener@gmail.com>
|
||||
Bruno Maia <bruno.mm.maia@gmail.com>
|
||||
Bryan Berger <bb@ga.co>
|
||||
C <4019980@qq.com>
|
||||
C.J. Winslow <whoaa512@gmail.com>
|
||||
Cam Song <neosoyn@gmail.com>
|
||||
Camol <kwwnjujlc@sina.com>
|
||||
Cang Ta <hoksilato176@gmail.com>
|
||||
Canwen Xu <canwenxu@126.com>
|
||||
Carter Feldman <carter@carter.at>
|
||||
Catalin Miron <mironcatalin@gmail.com>
|
||||
Cee Cirno <i@cee.moe>
|
||||
Chandler Moisen <chandlermoisen@gmail.com>
|
||||
Chang Wang <cheapsteak@gmail.com>
|
||||
Charles Covey-Brandt <chazcb@gmail.com>
|
||||
Chelsea Huang <chelsea.huang@sap.com>
|
||||
Chenjia <ariesjia00@hotmail.com>
|
||||
Chikara Chan <chenhongtu@51xianqu.net>
|
||||
Chris Kelly <cjke.7777@gmail.com>
|
||||
ChrisFan <chris.fan.dev@gmail.com>
|
||||
Christian <chr.vadala@gmail.com>
|
||||
Christian Vadalà <chr.vadala@gmail.com>
|
||||
Christopher Deutsch <cd@cdeutsch.com>
|
||||
Chuang Yu <cyu9960@gmail.com>
|
||||
Claudio Restifo <claudio.restifo@gmail.com>
|
||||
Cody Chan <int64ago@gmail.com>
|
||||
Colton Pierson <colton@coltonpierson.com>
|
||||
Confiks <confiks@scriptbase.org>
|
||||
Cong Zhang <dancerphil1994@gmail.com>
|
||||
Conway Anderson <hello@conwayanderson.com>
|
||||
Cordaro <elvis07@163.com>
|
||||
D & R <jdz321@qq.com>
|
||||
Daewoong Moon <wiziple@gmail.com>
|
||||
Damian Green <damian.green@microlease.com>
|
||||
Damian Green <damian@gcoders.com>
|
||||
Dan Minshew <ofenixculpa@gmail.com>
|
||||
Dane David <dndavid102@gmail.com>
|
||||
Daniel Gomez <dgomez@orangeloops.com>
|
||||
Danny Hoower Antonio Viasus Avila <danjavia@gmail.com>
|
||||
Daqi Song <dqaria@gmail.com>
|
||||
Darren Poon <dyhpoon@gmail.com>
|
||||
David Hatten <dhatten@covermymeds.com>
|
||||
David Schneider <davschne@gmail.com>
|
||||
DengYun <tdzl2003@gmail.com>
|
||||
Dimitri Mitropoulos <dimitrimitropoulos@gmail.com>
|
||||
Dmitriy Mironov <dima.dev01@gmail.com>
|
||||
Dmitry Bolotin <bolotin.dmitriy@gmail.com>
|
||||
Dmitry Gladkikh <abdurahmanus@gmail.com>
|
||||
Dmitry Guryev <dmitry.gurjev@gmail.com>
|
||||
Dmitry Manannikov <email@slonoed.net>
|
||||
Dmitry Snegirev <rikkitp@gmail.com>
|
||||
Dorian <dorian@doma.io>
|
||||
DosLin <doslino@gmail.com>
|
||||
Douglas Mason <Demasonjr@gmail.com>
|
||||
Eager <1226393396@qq.com>
|
||||
Eager Wei <1226393396@qq.com>
|
||||
EcmaProSrc.P/ka <asoiso@foxmail.com>
|
||||
Ed Moore <ed@90seconds.tv>
|
||||
Edd Hannay <accounts@edd.fm>
|
||||
Eddie Xie <oeddyo@gmail.com>
|
||||
Eden Wang <Eden.Wang@Akmii.com>
|
||||
Eden Wang <yociduo@vip.qq.com>
|
||||
Eduardo Ludi <eduludi@gmail.com>
|
||||
Edward <7047924@qq.com>
|
||||
Egor Yurtaev <yurtaev.egor@gmail.com>
|
||||
Eli White <github@eli-white.com>
|
||||
Emerson Laurentino <emersonlaurentino@hotmail.com>
|
||||
Emma <sima.zhang1990@gmail.com>
|
||||
Eric <84263800@qq.com>
|
||||
Eric Celeste <efc@clst.org>
|
||||
Eric Turriff <eric.turriff@gmail.com>
|
||||
Erwann Mest <m+github@kud.io>
|
||||
Evgeny Kuznetsov <jackk@ya.ru>
|
||||
Eward Song <eward.song@gmail.com>
|
||||
Federico Marcos <marcosfede@gmail.com>
|
||||
Fergus Leung <fergusleung96@gmail.com>
|
||||
Fernando Giarritiello <fgiarritiello@gmail.com>
|
||||
Flynn <li.fulin@foxmail.com>
|
||||
For177 <mengqiang.q@gmail.com>
|
||||
Gao Jiangmiao <tolbkni@gmail.com>
|
||||
Geoff Holden <geoff@brightloudnoise.com>
|
||||
George Gray <george@ummodesign.com>
|
||||
Graeme Yeates <gyeates@clearpath.ai>
|
||||
Graeme Yeates <yeatesgraeme@gmail.com>
|
||||
Grant Klinsing <gklinsing@gmail.com>
|
||||
Gray Choi <gray.choi.1988@gmail.com>
|
||||
Guan Hao <raptium@gmail.com>
|
||||
Guan Yu Pan (Jacky) <jackypan1989@gmail.com>
|
||||
HJin.me <hjin.me@gmail.com>
|
||||
Hai Phan Nguyen <pnghai@gmail.com>
|
||||
Haibin Yu <haibin.yu@oceanwing.com>
|
||||
Hanai <ihanai1991@gmail.com>
|
||||
Hanz Luo <lhz0516@gmail.com>
|
||||
Haroen Viaene <fingebimus@me.com>
|
||||
Harshit Mehrotra <harshitmehrotra@hotmail.com>
|
||||
Heaven <ne_smalltown@163.com>
|
||||
Henri Normak <henri.normak@gmail.com>
|
||||
HeskeyBaozi <hezhiyu233@foxmail.com>
|
||||
Hieu Ho <hieu.ho.le@lazada.com>
|
||||
Hubert Argasinski <argasinski.hubert@gmail.com>
|
||||
Hughen <446370503@163.com>
|
||||
Hugo LEHMANN <shogi31@gmail.com>
|
||||
Igor G <i.gaidai4uk@gmail.com>
|
||||
Ilan <hasanovtk@gmail.com>
|
||||
Ilan Hasanov <hasanovtk@gmail.com>
|
||||
ImJoeHs <865439601@qq.com>
|
||||
Inclined.Z <zjq0717@163.com>
|
||||
Infinity <305870677@qq.com>
|
||||
Ivan Kravets <me@ikravets.com>
|
||||
Ivan Trofimov <ivan@trofimov.link>
|
||||
Ivo Stratev <ivo.stratev.tues@gmail.com>
|
||||
Jack Hsieh <jack@egenware.com>
|
||||
Jack Works <zjwpeter@gmail.com>
|
||||
Jackie.Ls <418292038@qq.com>
|
||||
Jacques Kvam <jwkvam@gmail.com>
|
||||
JaePil Jung <jjp5023@gmail.com>
|
||||
Jake Richards <jake.richards@genesys.com>
|
||||
James <james@schoolshape.com>
|
||||
JamesYin <elantion@gmail.com>
|
||||
Jaroslav Bereza <github.com@bereza.cz>
|
||||
Jean-Luc Sorak <jlsorak@icloud.com>
|
||||
Jeffrey Carl Faden <jeffreyatw@gmail.com>
|
||||
JeromeLin <jerome.lin@zhongan.com>
|
||||
Jerry Bendy <jerry@icewingcc.com>
|
||||
Jesper We <jesper@journeyman.se>
|
||||
Jiabin Peng <png.inside@gmail.com>
|
||||
Jialei <jialeicui@126.com>
|
||||
Jieraaa <842533841@qq.com>
|
||||
Jin ZHANG <jz.zhangjin@gmail.com>
|
||||
Jing Ma <mjingm87@qq.com>
|
||||
Jinxuan Zhu <zhujinxuan@gmail.com>
|
||||
Joe <qiaolibo@126.com>
|
||||
Joe Hsu <jhsu.x1@gmail.com>
|
||||
Johannes Loewe <johannes@loewe.pm>
|
||||
John Johnson III <john@johnjohnson.cc>
|
||||
John Nguyen <jtnguyen236@gmail.com>
|
||||
Jonatas Walker <jonataswalker@gmail.com>
|
||||
Jonny Buchanan <jonathan.buchanan@gmail.com>
|
||||
Jordan Hornblow <jordan@jch254.com>
|
||||
Josué <ujosuegt@outlook.com>
|
||||
JribiBelhassen <belha9inzaghi@gmail.com>
|
||||
Juan Rodrigo Venegas Boesch <jrvboesch@gmail.com>
|
||||
Junyu Zhan <irrigator@yeah.net>
|
||||
Kaien Liao <liaokaien@gmail.com>
|
||||
Kenaniah Cerny <kenaniah@gmail.com>
|
||||
Kenneth Luján Rosas <elgenio.03@gmail.com>
|
||||
Kenneth Truong <kenneth.e.truong@gmail.com>
|
||||
KentonYu <975853613@qq.com>
|
||||
Kevin Ivan <info@kevinivan.com>
|
||||
Kevin Wang <gumtree200@gmail.com>
|
||||
KgTong <kgtong1992@gmail.com>
|
||||
Khalifa Lame <khalibloo@gmail.com>
|
||||
Kian <kian@vsu.cc>
|
||||
Kiho · Cham <monkindey@163.com>
|
||||
Kimmo Saari <kimmo.saari@revolt.fi>
|
||||
Kirill Alexander Khalitov <voronar@gmail.com>
|
||||
Kirill Stiopin <kirill.stiopin@hotmail.com>
|
||||
Knacktus <knacktus@gmail.com>
|
||||
Kyle Kelley <rgbkrk@gmail.com>
|
||||
Kyle Rosenberg <kyle.rosenberg@gmail.com>
|
||||
LLinFan- <catfoursi@qq.com>
|
||||
Laith <laith24@gmail.com>
|
||||
Larry Laski <larry.laski@gmail.com>
|
||||
LeeHarlan <709886167@qq.com>
|
||||
LeezQ <lizhenq2009@gmail.com>
|
||||
Leo <clinyong@gmail.com>
|
||||
Leon Shi <superRaytin@163.com>
|
||||
Leon Shi <superRaytin@gmail.com>
|
||||
Li Chao <rftstars@qq.com>
|
||||
Liu Yang <zation1@gmail.com>
|
||||
LongYinan <lynweklm@gmail.com>
|
||||
Lucien Lee <lkiral7903@gmail.com>
|
||||
Ludwig Bäcklund <ludli839@student.liu.se>
|
||||
Lyndon001 <lld207@126.com>
|
||||
MG12 <wuzhao.mail@gmail.com>
|
||||
Ma Tianxiao <matx2215@outlook.com>
|
||||
Madis Väin <madisvain@gmail.com>
|
||||
Manjit Kumar <manjit1727@gmail.com>
|
||||
Manweill <mic.liangwenwei@foxmail.com>
|
||||
Marcela Bomfim <mbomfim@live.com>
|
||||
Marco Afonso <mafonso333@gmail.com>
|
||||
Marcus Bransbury <marcus.bransbury@gmail.com>
|
||||
Marius Ileana <visvadw@gmail.com>
|
||||
Mars Wong <marswong618@gmail.com>
|
||||
Marshall Chen <Juniors.fei@gmail.com>
|
||||
Martin Litvaj <kamahl19@gmail.com>
|
||||
Martin Novák <martinnovak@outlook.com>
|
||||
Mathew <khayaanimations@gmail.com>
|
||||
Matt Lein <matt.lein@code42.com>
|
||||
Maximilian Meyer <Maximilian.Meyer@br.de>
|
||||
Meck <yesmeck@gmail.com>
|
||||
MeiLin <postget.me@gmail.com>
|
||||
Meow-z <372086270@qq.com>
|
||||
Miaow <i@zfeng.net>
|
||||
Michael Krog <michael.krog@previsto.com>
|
||||
Michael Wang <ylzcylx@gmail.com>
|
||||
Michalis Macheras <diodosier@gmail.com>
|
||||
Mikasa33 <mikasa33@qq.com>
|
||||
Min <dicklwm@163.com>
|
||||
MinJeong Kim <min7859@gmail.com>
|
||||
Minqi Pan <pmq2001@gmail.com>
|
||||
Minsung Ryu <ryums0227@gmail.com>
|
||||
Mitchell Demler <mitchell.demler@harcourts.net>
|
||||
Mohamed Seada <mohamed.seada.1994@gmail.com>
|
||||
Mohammad Faisal <faisalhmohd@gmail.com>
|
||||
Mr.Tone <vector@malubei.com>
|
||||
MuYu <mr.muzea@gmail.com>
|
||||
Mário Gonçalves <mario.mc.goncalves@gmail.com>
|
||||
Nathan Griffin <nathan@gatherhere.com>
|
||||
Nathan Tavares Nascimento <nathan.tnascimento@gmail.com>
|
||||
Nathan Wells <nwwells@gmail.com>
|
||||
Neekey <ni184775761@gmail.com>
|
||||
Nekron <nekron.hyt@gmail.com>
|
||||
Neverland <chenjiahan@buaa.edu.cn>
|
||||
Nico <nicolas@freddelacompta.com>
|
||||
Nidhi Agarwal <nidhi.agarwal@zomato.com>
|
||||
Nikolay <veseliy07@gmail.com>
|
||||
Nikolay Solovyov <i@mr-ozio.ru>
|
||||
Nimo <nimo.jser@gmail.com>
|
||||
Nishant Arora <na.nishantarora@gmail.com>
|
||||
Nokecy <Nokecy@163.com>
|
||||
OAwan <georgio.wan@gmail.com>
|
||||
Oleg Kuzava <olegkuzava@gmail.com>
|
||||
Oleksandr Kovalchuk <me.olexandr.kovalchuk@gmail.com>
|
||||
Ooi Yee Wei <ywooi@yahoo.com>
|
||||
Open Next <opennext@126.com>
|
||||
OuYancey <ou.yancey@gmail.com>
|
||||
Panjie Setiawan Wicaksono <panjie@panjiesw.com>
|
||||
Patrick Gidich <patrick.gidich@simnova.com>
|
||||
Patryk <longer44@gmail.com>
|
||||
Peter <usstpeter@gmail.com>
|
||||
Peter Berg <atticusberg@gmail.com>
|
||||
Phanupong Janthapoon <panupong.jtp@gmail.com>
|
||||
Pierre <pierre@bazoge.com>
|
||||
Pierre Neter <pierreneter@gmail.com>
|
||||
Piper Chester <piperchester@gmail.com>
|
||||
Pixy Yuan <pixy.bupt@gmail.com>
|
||||
Pooya Parsa <pyapar@gmail.com>
|
||||
Pyiner <lijiuyang1992@gmail.com>
|
||||
Pyroboomka <qwaarty@mail.ru>
|
||||
Qiaosen Huang <joesonw@gmail.com>
|
||||
Qingrong Ke <keqingrong1992@gmail.com>
|
||||
Rafael Cosman <rafaelcosman@alumni.stanford.edu>
|
||||
Rahul Gurung <gurungrahul2@gmail.com>
|
||||
Rallets <rallet@rallets.com>
|
||||
Ramsés Moreno <ramses@cuatromedios.com>
|
||||
Randy <randypriv@gmail.com>
|
||||
RaoHai <surgesoft@gmail.com>
|
||||
Raphael Chauveau <raph.chauveau@gmail.com>
|
||||
Reed Sun <superreedsun@gmail.com>
|
||||
Rex <zhangzilong.zzl@163.com>
|
||||
Ricardo Raphael Joson <rrjoson08@gmail.com>
|
||||
Richard D. Worth <rdworth@gmail.com>
|
||||
Rick Zhou <rinick@gmail.com>
|
||||
Robert Wilkinson <wilkinson.robert.a@gmail.com>
|
||||
Rohan Malhotra <rohan.root@gmail.com>
|
||||
Rongjian Zhang <pd4d10@gmail.com>
|
||||
Rrrandom <emanonhere@gmail.com>
|
||||
RyanHui <ryanhui1996@gmail.com>
|
||||
SHEN Lin <shenlin192@gmail.com>
|
||||
Sakol Assawasagool <koobitor@gmail.com>
|
||||
Sam Chen <chenxsan@gmail.com>
|
||||
Sam Maxwell <sam@paybase.io>
|
||||
Samuel Gaus <sam@gaus.co.uk>
|
||||
Sangle <whb97@163.com>
|
||||
Sanjay Kumar <kris.gooner@gmail.com>
|
||||
Sanjay Kumar <sk@tectusdreamlab.com>
|
||||
Scott Sturgeon <scott@tugboatlogic.com>
|
||||
Sean Lin <sean@ejoy.com>
|
||||
Sean Sun <pinggodstudio@gmail.com>
|
||||
Sebastian Blade <blade254353074@hotmail.com>
|
||||
Sebastian Busch <mail@sebastian-bus.ch>
|
||||
Sebastian Busch <s.busch@qbus-enet.de>
|
||||
Sergio Crisostomo <sergiosbox@gmail.com>
|
||||
Shawn Sit <xueqingxiao@gmail.com>
|
||||
ShiTengFei <shitengfei@goyoo.com>
|
||||
Shubham Kanodia <shubhamsizzles@gmail.com>
|
||||
Shun <polytechnics.shun@gmail.com>
|
||||
Shuvalov Anton <anton@shuvalov.info>
|
||||
SimaQ <sima.zhang1990@gmail.com>
|
||||
Spencer <spjy@hawaii.edu>
|
||||
Stephen Esser <Stephen.Esser@gmail.com>
|
||||
Tao <magicdawn@qq.com>
|
||||
Tao Zhang <windse7en@gmail.com>
|
||||
Taylor Sabell <taylorsabell@gmail.com>
|
||||
Tengjiao Cai <caitengjiao1987@gmail.com>
|
||||
Terence <trence320@163.com>
|
||||
The Rock <zhoguoxin@126.com>
|
||||
Thibault Derousseaux <tde@activeviam.com>
|
||||
Thiebaud Thomas <thiebaud.tom@gmail.com>
|
||||
Tino D <ginodeis@gmail.com>
|
||||
Tom Gao <tom@zoomsoft.cc>
|
||||
Tom Xu <tom.xu@antcosa.com>
|
||||
Tom Xu <ycxzhkx@gmail.com>
|
||||
TomIsion <isiontom@gmail.com>
|
||||
Tomás Francisco <mail@tomasfrancisco.com>
|
||||
Tomáš Szabo <tomas.szabo@deftomat.com>
|
||||
Trotyl Yu <trotyl@qq.com>
|
||||
Troy Thompson <troynt@gmail.com>
|
||||
Tyler <chaotyler@gmail.com>
|
||||
Ubaldo Quintana <blkdr@hotmail.com>
|
||||
Vadim Macagon <vadim.macagon@gmail.com>
|
||||
Valentin Vichnal <valentin@vichnal.com>
|
||||
Vemund Santi <vemund@santi.no>
|
||||
Vic <709147950@qq.com>
|
||||
Vemund Santi <veund@santi.no>
|
||||
Vincent Zhang <vxzhong@qq.com>
|
||||
Vitaliy Mazurenko <vitaliymazurenko@gmail.com>
|
||||
ViviaRui <zr1450995198@163.com>
|
||||
Walter Barbagallo <brb.walter@gmail.com>
|
||||
Walter Barbagallo <turbometalskater@gmail.com>
|
||||
Wang Jun <amos.callmexyz@gmail.com>
|
||||
Wang Riwu <riwu0730@gmail.com>
|
||||
Wang Zhengchen <wang909208@163.com>
|
||||
Warren Seymour <warren@fountainhead.tech>
|
||||
Wei Zhu <yesmeck@gmail.com>
|
||||
Wenchao Hu <zjuhwc@gmail.com>
|
||||
Wendell <wendzhue@gmail.com>
|
||||
Will Chen <willchen90@gmail.com>
|
||||
WingGao <wing.gao@live.com>
|
||||
Wu Haotian <whtsky@gmail.com>
|
||||
XBTop1! <xbtop1@gmail.com>
|
||||
Xiaoming <yokiming1994@gmail.com>
|
||||
Xie Guanglei <xieguanglei@hotmail.com>
|
||||
Xiping.wang <527409987@qq.com>
|
||||
XuMM_12 <owiatsq@sina.cn>
|
||||
Yang <504021398@qq.com>
|
||||
Yang Bin <yangkghjh@gmail.com>
|
||||
Yasin Uslu <nepjua@gmail.com>
|
||||
Yevhen Hryhorevskyi <evgeniygrigorevskiy@gmail.com>
|
||||
Yiming <ymjrcc@qq.com>
|
||||
Yogesh <yogeshkumar180592@gmail.com>
|
||||
Yu <yutingzhao1991@sina.com>
|
||||
YuChao Liang <l.yuch@foxmail.com>
|
||||
Yuhang Liu <644186735@qq.com>
|
||||
Yunus EŞ <yunus@yunuses.com>
|
||||
Yuri Pirola <yuri.pirola@unimi.it>
|
||||
Yury Kozyrev <urakozz@me.com>
|
||||
Yusuke Ito <novi.mad@gmail.com>
|
||||
Yuwei Ba <i@xiaoba.me>
|
||||
Yuxuan Huo <yuxuan.huo2011@gmail.com>
|
||||
YuyingWu <wuyuying1128@gmail.com>
|
||||
Zack Craig <zack@zack6849.com>
|
||||
Zap <a124116186@qq.com>
|
||||
Zhang Zhi <fytriht@gmail.com>
|
||||
Zheeeng <hi@zheeeng.me>
|
||||
Zhiqiang Gong <elory0513@hotmail.com>
|
||||
Ziluo <gyfzzu@gmail.com>
|
||||
Zohaib Ijaz <mzohaib.qc@gmail.com>
|
||||
afc163 <afc163@gmail.com>
|
||||
agent-z <1607291079@qq.com>
|
||||
ahalimkara <ahalimkara@gmail.com>
|
||||
alex <379118572@qq.com>
|
||||
arifemrecelik <ce.arifemre@gmail.com>
|
||||
ascoders <576625322@qq.com>
|
||||
ashishg-qburst <ashishg@qburst.com>
|
||||
bLue <tbdblue@gmail.com>
|
||||
bang <sqibang@gmail.com>
|
||||
bang88 <sqibang@gmail.com>
|
||||
baozefeng <727751065@qq.com>
|
||||
blankzust <450811238@qq.com>
|
||||
byuanama <byuan@ama.com.au>
|
||||
byzyk <bohdan.kh@gmail.com>
|
||||
bzone <yarnbcoder@gmail.com>
|
||||
caoyi <caoyi0905@mail.hfut.edu.cn>
|
||||
carrie-tanminyi <12mytan@gmail.com>
|
||||
cathayandy <wzm_andy@126.com>
|
||||
chaofeis <408067385@qq.com>
|
||||
chchen <cc272309126@gmail.com>
|
||||
chencheng (云谦) <sorrycc@gmail.com>
|
||||
chencheng <sorrycc@gmail.com>
|
||||
cjahv <cjahv@qq.com>
|
||||
clinyong <clinyong@gmail.com>
|
||||
codesign <zuishiguang@126.com>
|
||||
corneyl <cornieljoosse@gmail.com>
|
||||
david.lv <code4funlnyx@gmail.com>
|
||||
davidhatten <david.r.hatten@gmail.com>
|
||||
ddcat1115 <ddcat1115@gmail.com>
|
||||
decade <decadef20@gmail.com>
|
||||
delesseps <andrewlessels@gmail.com>
|
||||
denzw <denzw@21cn.com>
|
||||
dependabot[bot] <support@dependabot.com>
|
||||
detailyang <detailyang@gmail.com>
|
||||
devqin <devqin@gmail.com>
|
||||
digz6666 <digz6666@gmail.com>
|
||||
djorkaeff <djorkae55@gmail.com>
|
||||
duzliang <duzliang@gmail.com>
|
||||
ecofe <150641329@qq.com>
|
||||
@@ -436,221 +180,101 @@ ezpub <ez.foro@gmail.com>
|
||||
feng zhi hao <fzhihao@outlook.com>
|
||||
fengmk2 <m@fengmk2.com>
|
||||
flashback313 <windmark2012@gmail.com>
|
||||
frezc <504021398@qq.com>
|
||||
genie <genie88@163.com>
|
||||
gregahren <grega.hren@gmail.com>
|
||||
guifu <picodoth@gmail.com>
|
||||
handycode <lihandi@gmail.com>
|
||||
hank <stonehank310@gmail.com>
|
||||
hanpei <75189218@qq.com>
|
||||
hansnow <hansnow2012@gmail.com>
|
||||
haoxin <coderhaoxin@outlook.com>
|
||||
hardfist <yangjianzju@gmail.com>
|
||||
hauwa123 <hauwa.aminu@outlook.com>
|
||||
hehe <xpc_kacl@163.com>
|
||||
hengkx <ycxzhkx@gmail.com>
|
||||
henryv0 <henryvo94@gmail.com>
|
||||
hi-caicai <hi@cai-cai.me>
|
||||
hongxuWei <hongxu.wei@outlook.com>
|
||||
huangyan.py <huangyan.py@bytedance.com>
|
||||
huzzbuzz <huzzbuzz@outlook.com>
|
||||
iamcastelli <sowed@cyberdude.com>
|
||||
ilanus <hasanovtk@gmail.com>
|
||||
imosapatryk <imosa.patryk@gmail.com>
|
||||
infeng <fzhihao@outlook.com>
|
||||
int2d <int2d@qq.com>
|
||||
ioldfish <fish.wangl@gmail.com>
|
||||
jasonslyvia <jasonslyvia@gmail.com>
|
||||
jasonxia23 <xia.jason23@gmail.com>
|
||||
jiang <155259966@qq.com>
|
||||
jim <wasd2144@hotmail.com>
|
||||
jinouwuque <ee2win@gmail.com>
|
||||
jinyaqiao1102 <405782493@QQ.com>
|
||||
jojoLockLock <miffyschou@sina.com>
|
||||
junjing.zhang <zhangjunjing@gmail.com>
|
||||
kacjay <45483388@qq.com>
|
||||
kagawagao <kingsongao1221@gmail.com>
|
||||
kaifei <150641329@qq.com>
|
||||
kasinooya <kasinooya@gmail.com>
|
||||
kayw <kayw@outlook.com>
|
||||
kdenz <ksnz93@gmail.com>
|
||||
kdepp <kdepp.cd@gmail.com>
|
||||
keng <keng@renderinghouse.com>
|
||||
keqingrong <keqingrong1992@gmail.com>
|
||||
ko <git@yaksok.net>
|
||||
konakona <lovekonakona@gmail.com>
|
||||
kossel <lis.yichao@gmail.com>
|
||||
kuang <p2227@hotmail.com>
|
||||
kuitos <kuitos.lau@gmail.com>
|
||||
kun sam <kunsam624@icloud.com>
|
||||
leadream <857098475@qq.com>
|
||||
lehug <zcszuo5811@126.com>
|
||||
leijingdao <leijingdao@163.com>
|
||||
leon.shi <superRaytin@163.com>
|
||||
lgmcolin <gengmin.lgm@gmail.com>
|
||||
lgmcolin <lgmcolin@gmail.com>
|
||||
liangfei <njliangfei@gmail.com>
|
||||
liekkas <zjq0717@163.com>
|
||||
lihqi <455711093@qq.com>
|
||||
littleLane <857183384@qq.com>
|
||||
lixiaochou077 <qi.liqi07@gmail.com>
|
||||
lixiaoyang <lixiaoyang2345@gmail.com>
|
||||
lixiaoyang1992 <lixiaoyang2345@gmail.com>
|
||||
lizhaocai <lzc09008@gmail.com>
|
||||
lizhen <lizhen@youzan.com>
|
||||
loganpowell <loganp@tepper.cmu.edu>
|
||||
luyiming <luyimingchn@gmail.com>
|
||||
lvren <luren6049@qq.com>
|
||||
mArker <252133226@qq.com>
|
||||
memoryza <jincai.wang@foxmail.com>
|
||||
mgrdevport <mgrdevport@gmail.com>
|
||||
mitchell.demler <mitchell.demler@harcourts.net>
|
||||
mkermani144 <mkermani144@gmail.com>
|
||||
mmmveggies <jakeselig@gmail.com>
|
||||
mofelee <mofe@me.com>
|
||||
monkindey <monkindey@163.com>
|
||||
mushan0x0 <mushan0x0@gmail.com>
|
||||
muzea <mr.muzea@gmail.com>
|
||||
muzuiget <muzuiget@gmail.com>
|
||||
natergj <nater_nater@me.com>
|
||||
neekey <ni184775761@gmail.com>
|
||||
niko <644506165@qq.com>
|
||||
nikogu <644506165@qq.com>
|
||||
nuintun <nuintun@qq.com>
|
||||
ohhoney1 <1269075501@qq.com>
|
||||
paranoidjk <hust2012jiangkai@gmail.com>
|
||||
parlop <parlop@gmail.com>
|
||||
pbrink231 <pbrink231@gmail.com>
|
||||
pd4d10 <pd4d10@gmail.com>
|
||||
peiming <hyrijk@gmail.com>
|
||||
picodoth <picodoth@gmail.com>
|
||||
picodoth <pikaleize@gmail.com>
|
||||
pinggod <pinggodstudio@gmail.com>
|
||||
pizn <pizner@gmail.com>
|
||||
plandem <plandem@gmail.com>
|
||||
popomore <sakura9515@gmail.com>
|
||||
qiaojie <1454763497@qq.com>
|
||||
qixian.cs@outlook.com <wasd2144@hotmail.com>
|
||||
qliu <1403927509@qq.com>
|
||||
qubaoming <qubaoming@didichuxing.com>
|
||||
ravirambles <ravirambles@gmail.com>
|
||||
ryangun <ryangun@foxmail.com>
|
||||
ryanhoho <hswacoal@gmail.com>
|
||||
ryannz <c5e1856@gmail.com>
|
||||
sadmark <zhoubin@laidian360.com>
|
||||
sallen450 <jqh101@sina.com>
|
||||
shelwin <wxfans@gmail.com>
|
||||
shenlin192@gmail.com <shenlin192@gmail.com>
|
||||
shlice <licesh@gmail.com>
|
||||
shouyong <enlangs@163.com>
|
||||
simaQ <sima.zhang1990@gmail.com>
|
||||
siyu77 <xwzhang1986@gmail.com>
|
||||
slientcloud <rjmuqiang@gmail.com>
|
||||
sliwey <qlw1009@gmail.com>
|
||||
snadn <snadn@snadn.cn>
|
||||
snail <120216220@qq.com>
|
||||
sojournerc <cmeyer@zvelo.com>
|
||||
sorrycc <sorrycc@gmail.com>
|
||||
sosohime <theziming@126.com>
|
||||
spideeee <spideeee@github.com>
|
||||
stickmy <stickmyc@gmail.com>
|
||||
swindme <swindme@163.com>
|
||||
syssam <s.y.s.sam.sys@gmail.com>
|
||||
tangjinzhou <415800467@qq.com>
|
||||
tangjinzhou <tangjinzhou@yidian-inc.com>
|
||||
thegatheringstorm <tgs@tgs.blue>
|
||||
tianli.zhao <275287902@qq.com>
|
||||
tom <caolvchong@gmail.com>
|
||||
twobin <twobin@live.com>
|
||||
u3u <qwq@qwq.cat>
|
||||
ustccjw <317713370@qq.com>
|
||||
valleykid <valleykiddy@gmail.com>
|
||||
vgeyi <vgeyiz@126.com>
|
||||
wangshantao <605682551@qq.com>
|
||||
wangtao0101 <yuecjn@gmail.com>
|
||||
wangxiaolei <fatelei@gmail.com>
|
||||
wangxueliang <wangxueliang@yidian-inc.com>
|
||||
warmhug <hualei5280@gmail.com>
|
||||
whtang906 <whtang906@gmail.com>
|
||||
wizawu <wizawu@gmail.com>
|
||||
wonyun <wy393767068@163.com>
|
||||
xiaofan2406 <xiaofan2406@gmail.com>
|
||||
y-take <y.takey@gmail.com>
|
||||
yangwukang <yangwukang@boco.com.cn>
|
||||
ycjcl868 <45808948@qq.com>
|
||||
yeliex <yeliex@yeliex.com>
|
||||
yiminanci <yiminanci@gmail.com>
|
||||
yiminghe <yiminghe@gmail.com>
|
||||
yociduo <yociduo@vip.qq.com>
|
||||
yoyo837 <yoyo837@hotmail.com>
|
||||
yubozhao <yubz86@gmail.com>
|
||||
yuche <i@yuche.me>
|
||||
z <haig8@msn.com>
|
||||
zack <zxyah@126.com>
|
||||
zelongc <nickcong123@gmail.com>
|
||||
zerob4wl <zerob4wl@gmail.com>
|
||||
zhangpc <zhangpc@tenxcloud.com>
|
||||
zhaocai <lzc09008@gmail.com>
|
||||
zhujun24 <zhujun87654321@gmail.com>
|
||||
zhuyue <fuping.dfp@antfin.com>
|
||||
zilong <jzlxiaohei@163.com>
|
||||
zinkey <yaya@uloveit.com.cn>
|
||||
zollero <corona7@163.com>
|
||||
zombieJ <smith3816@gmail.com>
|
||||
zombiej <smith3816@gmail.com>
|
||||
zongzi531 <zongzi.xy@gmail.com>
|
||||
ztplz <mysticzt@gmail.com>
|
||||
zuiidea <zuiiidea@gmail.com>
|
||||
°))))彡 <fisherspy@live.com>
|
||||
邦 <sqibang@gmail.com>
|
||||
爱but的苍蝇 <354788473@qq.com>
|
||||
高力 <3071730@qq.com>
|
||||
拷钉 <41830859@qq.com>
|
||||
苏秦 <646382806@qq.com>
|
||||
竹尔 <Juelchiang@gmail.com>
|
||||
偏右 <afc163@gmail.com>
|
||||
英布 <chaoren1641@gmail.com>
|
||||
朮厃 <cn.ah.liu@gmail.com>
|
||||
张聪 <dancerphil1994@gmail.com>
|
||||
诸岳 <dengfuping_develop@163.com>
|
||||
逸达 <dqaria@gmail.com>
|
||||
诸岳 <fuping.dfp@antfin.com>
|
||||
刘红 <liuhong1.happy@163.com>
|
||||
宝码 <noyobo@gmail.com>
|
||||
陈帅 <qixian.cs@outlook.com>
|
||||
蔡伦 <sliuqin@gmail.com>
|
||||
陆离 <surgesoft@gmail.com>
|
||||
愚道 <tingzhao.ytz@antfin.com>
|
||||
陈帅 <wasd2144@hotmail.com>
|
||||
松子 <window.pibarr@gmail.com>
|
||||
付引 <xxxquotes@gmail.com>
|
||||
可乐 <zaxlct@foxmail.com>
|
||||
山客 <zeakhold@gmail.com>
|
||||
曾凯 <zengkai2009@foxmail.com>
|
||||
低位 <zhujun87654321@gmail.com>
|
||||
广彬-梁 <326741518@qq.com>
|
||||
何志勇 <15988134176@163.com>
|
||||
徐坤龙 <272992168@qq.com>
|
||||
黄子毅 <576625322@qq.com>
|
||||
翁润雨 <593110501@qq.com>
|
||||
崔宏森 <948346354@qq.com>
|
||||
黄文鉴 <concefly@foxmail.com>
|
||||
董天成 <dongtiangche@outlook.com>
|
||||
方剑成 <fjc0kb@gmail.com>
|
||||
包子熊 <hezhiyu233@foxmail.com>
|
||||
闲耘™ <hotoo.cn@gmail.com>
|
||||
一喵呜 <hyb628@gmail.com>
|
||||
吕立青 <jimmy.jinglv@gmail.com>
|
||||
隋鑫磊 <joshuasui@gmail.com>
|
||||
乔奕轩 <qiao_yixuan@163.com>
|
||||
马斯特 <sd4399340@126.com>
|
||||
王集鹄 <wjhu111@21cn.com>
|
||||
低位 <zhujun87654321@gmail.com>
|
||||
偏右 <afc163@gmail.com>
|
||||
可乐 <zaxlct@foxmail.com>
|
||||
吕立青 <jimmy.jinglv@gmail.com>
|
||||
广彬-梁 <326741518@qq.com>
|
||||
柚子男 <yozman@sina.com>
|
||||
愚指导 <yutingzhao1991@sina.com>
|
||||
愚指导-TZ <yutingzhao1991@sina.com>
|
||||
杨小事er <Uiryzd@163.com>
|
||||
超能刚哥 <margox@foxmail.com>
|
||||
马金花儿 <o.o@mug.dog>
|
||||
रोहन मल्होत्रा <rohan.malhotra@adwyze.com>
|
||||
白羊座小葛 <abeyuhang@gmail.com>
|
||||
薛定谔的猫 <hh_2013@foxmail.com>
|
||||
英布 <chaoren1641@gmail.com>
|
||||
蔡伦 <sliuqin@gmail.com>
|
||||
逸达 <dqaria@gmail.com>
|
||||
邦 <sqibang@gmail.com>
|
||||
闲耘™ <hotoo.cn@gmail.com>
|
||||
陆离 <surgesoft@gmail.com>
|
||||
陈帅 <wasd2144@hotmail.com>
|
||||
马斯特 <sd4399340@126.com>
|
||||
马金花儿 <o.o@mug.dog>
|
||||
黄子毅 <576625322@qq.com>
|
||||
|
||||
2876
CHANGELOG.en-US.md
2876
CHANGELOG.en-US.md
File diff suppressed because it is too large
Load Diff
2742
CHANGELOG.zh-CN.md
2742
CHANGELOG.zh-CN.md
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,7 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version].
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2015-present Ant UED, https://xtech.antfin.com/
|
||||
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,63 +1,49 @@
|
||||
<p align="center">
|
||||
<a href="http://ant.design">
|
||||
<img width="200" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
|
||||
<img width="320" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Ant Design</h1>
|
||||
# Ant Design
|
||||
|
||||
<div align="center">
|
||||
[](https://travis-ci.org/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://gemnasium.com/ant-design/ant-design)
|
||||
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](https://npmjs.org/package/antd)
|
||||
[](http://isitmaintained.com/project/ant-design/ant-design "Percentage of issues still open")
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) (English)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)(中文)
|
||||
|
||||
一套企业级的 UI 设计语言和 React 实现。
|
||||
|
||||
[](https://dev.azure.com/ant-design/ant-design/_build/latest?definitionId=2?branchName=master)
|
||||
[](https://circleci.com/gh/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](http://npmjs.com/antd)
|
||||
[](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
||||
[README in English](README.md)
|
||||
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/alerts/)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield)
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
</div>
|
||||
|
||||
[](http://ant.design/index-cn)
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
## ✨ 特性
|
||||
## 特性
|
||||
|
||||
- 提炼自企业级中后台产品的交互语言和视觉风格。
|
||||
- 开箱即用的高质量 React 组件。
|
||||
- 使用 TypeScript 构建,提供完整的类型定义文件。
|
||||
- 全链路开发和设计工具体系。
|
||||
- 基于 npm + webpack + [dva](https://github.com/dvajs/dva) 的企业级开发框架。
|
||||
|
||||
## 🖥 支持环境
|
||||
## 支持环境
|
||||
|
||||
* 现代浏览器和 IE9 及以上。
|
||||
* 支持服务端渲染。
|
||||
* [Electron](http://electron.atom.io/)
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron |
|
||||
| --------- | --------- | --------- | --------- | --------- | --------- |
|
||||
| IE9, IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions| last 2 versions
|
||||
## 参与共建 [](http://makeapullrequest.com)
|
||||
|
||||
## 📦 安装
|
||||
`antd` 是一个开源项目,我们欢迎社区参与共建。如果你对此项目感兴趣,有 [很多方式](https://opensource.guide/how-to-contribute/) 进行参与。你可以 watch 这个仓库,加入 [issue 中的讨论](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3ADiscussion),以及尝试实现一些 [已接受的特性](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22PR+welcome%22)。我们会给予有活跃贡献的社区成员 [collaborator 权限](https://github.com/ant-design/ant-design/issues/3222)。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm install antd --save
|
||||
npm install antd
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn add antd
|
||||
```
|
||||
|
||||
## 🔨 示例
|
||||
## 示例
|
||||
|
||||
```jsx
|
||||
import { DatePicker } from 'antd';
|
||||
@@ -70,54 +56,63 @@ 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
|
||||
|
||||
参考 [在 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)。
|
||||
|
||||
## 链接
|
||||
|
||||
- [首页](http://ant.design/)
|
||||
- [组件库](http://ant.design/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [更新日志](CHANGELOG.en-US.md)
|
||||
- [脚手架市场](http://scaffold.ant.design)
|
||||
- [React 底层基础组件](http://react-component.github.io/)
|
||||
- [移动端组件](http://mobile.ant.design)
|
||||
- [首页模板集](https://landing.ant.design)
|
||||
- [动效](https://motion.ant.design)
|
||||
- [脚手架市场](http://scaffold.ant.design)
|
||||
- [设计规范速查手册](https://github.com/ant-design/ant-design/wiki/Ant-Design-%E8%AE%BE%E8%AE%A1%E5%9F%BA%E7%A1%80%E7%AE%80%E7%89%88)
|
||||
- [开发者说明](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://ant.design/docs/react/faq-cn)
|
||||
- [CodeSandbox 模板](https://u.ant.design/codesandbox-repro) for bug reports
|
||||
- [常见问题](https://github.com/ant-design/ant-design/wiki/FAQ)
|
||||
- [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)
|
||||
|
||||
## ⌨️ 本地开发
|
||||
## 本地开发
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:ant-design/ant-design.git
|
||||
$ cd ant-design
|
||||
$ npm install
|
||||
$ npm start
|
||||
```
|
||||
|
||||
打开浏览器访问 http://127.0.0.1:8001 ,更多[本地开发文档](https://github.com/ant-design/ant-design/wiki/Development)。
|
||||
打开浏览器访问 http://127.0.0.1:8001 ,更多本地开发文档参见: https://github.com/ant-design/ant-design/wiki/Development 。
|
||||
|
||||
## 🤝 参与共建 [](http://makeapullrequest.com)
|
||||
## 如何贡献
|
||||
|
||||
请参考[贡献指南](https://ant.design/docs/react/contributing-cn).
|
||||
在任何形式的参与前,请先阅读 [贡献者文档](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),更好的问题更容易获得帮助。
|
||||
|
||||
[](https://issuehunt.io/repos/34526884)
|
||||
|
||||
## 社区互助
|
||||
|
||||
如果您在使用的过程中碰到问题,可以通过下面几个途径寻求帮助,同时我们也鼓励资深用户通过下面的途径给新人提供帮助。
|
||||
|
||||
138
README.md
138
README.md
@@ -1,63 +1,49 @@
|
||||
<p align="center">
|
||||
<a href="http://ant.design">
|
||||
<img width="200" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
|
||||
<img width="320" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Ant Design</h1>
|
||||
# Ant Design
|
||||
|
||||
<div align="center">
|
||||
|
||||
An enterprise-class UI design language and React implementation.
|
||||
|
||||
[](https://dev.azure.com/ant-design/ant-design/_build/latest?definitionId=2?branchName=master)
|
||||
[](https://circleci.com/gh/ant-design/ant-design)
|
||||
[](https://travis-ci.org/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://gemnasium.com/ant-design/ant-design)
|
||||
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](http://npmjs.com/antd)
|
||||
[](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
||||
[](https://npmjs.org/package/antd)
|
||||
[](http://isitmaintained.com/project/ant-design/ant-design "Percentage of issues still open")
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) (English)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)(中文)
|
||||
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/alerts/)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fant-design%2Fant-design?ref=badge_shield)
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
An enterprise-class UI design language and React-based implementation.
|
||||
|
||||
</div>
|
||||
[中文 README](README-zh_CN.md)
|
||||
|
||||
[](http://ant.design)
|
||||
## Features
|
||||
|
||||
English | [简体中文](./README-zh_CN.md)
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- An enterprise-class UI design system for web applications.
|
||||
- An enterprise-class UI design language for web applications.
|
||||
- A set of high-quality React components out of the box.
|
||||
- Written in TypeScript with predictable static types.
|
||||
- The whole package of development and design resources and tools.
|
||||
- Written in TypeScript with complete define types.
|
||||
- A npm + webpack + [dva](https://github.com/dvajs/dva) front-end development workflow.
|
||||
|
||||
## 🖥 Environment Support
|
||||
## Environment Support
|
||||
|
||||
* Modern browsers and Internet Explorer 9+ (with [polyfills](https://ant.design/docs/react/getting-started#Compatibility))
|
||||
* Server-side Rendering
|
||||
* [Electron](http://electron.atom.io/)
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron |
|
||||
| --------- | --------- | --------- | --------- | --------- | --------- |
|
||||
| IE9, IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions| last 2 versions
|
||||
## Let's build a better antd together [](http://makeapullrequest.com)
|
||||
|
||||
## 📦 Install
|
||||
`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
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn add antd
|
||||
```
|
||||
|
||||
## 🔨 Usage
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import { DatePicker } from 'antd';
|
||||
@@ -70,51 +56,95 @@ 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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🌍 Internationalization
|
||||
> 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
|
||||
|
||||
See [i18n](http://ant.design/docs/react/i18n).
|
||||
|
||||
## 🔗 Links
|
||||
## Links
|
||||
|
||||
- [Home page](http://ant.design/)
|
||||
- [Components](http://ant.design/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Change Log](CHANGELOG.en-US.md)
|
||||
- [Scaffold Market](http://scaffold.ant.design)
|
||||
- [rc-components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
- [Landing Pages](https://landing.ant.design)
|
||||
- [Motion](https://motion.ant.design)
|
||||
- [Scaffold Market](http://scaffold.ant.design)
|
||||
- [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://ant.design/docs/react/faq)
|
||||
- [CodeSandbox Template](https://u.ant.design/codesandbox-repro) for bug reports
|
||||
- [FAQ](https://github.com/ant-design/ant-design/wiki/FAQ)
|
||||
- [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)
|
||||
|
||||
## ⌨️ Development
|
||||
## Development
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:ant-design/ant-design.git
|
||||
$ cd ant-design
|
||||
$ npm install
|
||||
$ npm start
|
||||
```
|
||||
|
||||
Open your browser and visit http://127.0.0.1:8001 , see more at [Development](https://github.com/ant-design/ant-design/wiki/Development).
|
||||
Open your browser and visit http://127.0.0.1:8001 , see more at https://github.com/ant-design/ant-design/wiki/Development .
|
||||
|
||||
## 🤝 Contributing [](http://makeapullrequest.com)
|
||||
|
||||
Read our [contributing guide](https://ant.design/docs/react/contributing) and let's build a better antd together.
|
||||
## Contributing
|
||||
|
||||
We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)
|
||||
|
||||
If you are collaborator. Please follow our [Pull Request principle](https://github.com/ant-design/ant-design/wiki/PR-principle) to create Pull Request by [collaborator template](https://github.com/ant-design/ant-design/compare?expand=1&template=collaborator.md).
|
||||
|
||||
[](https://issuehunt.io/repos/34526884)
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
# Node.js
|
||||
# Build a general Node.js project with npm.
|
||||
# Add steps that analyze code, save build artifacts, deploy, and more:
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
|
||||
name: ant design
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
exclude:
|
||||
- gh-pages
|
||||
|
||||
jobs:
|
||||
- job: test_
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
strategy:
|
||||
matrix:
|
||||
Lint:
|
||||
TEST_TYPE: lint
|
||||
dist-react@16:
|
||||
REACT: 16
|
||||
TEST_TYPE: test:dist
|
||||
lib-react@16:
|
||||
REACT: 16
|
||||
TEST_TYPE: test:lib
|
||||
es-react@16:
|
||||
REACT: 16
|
||||
TEST_TYPE: test:es
|
||||
dom-react@16:
|
||||
REACT: 16
|
||||
TEST_TYPE: test:dom
|
||||
node-react@16:
|
||||
REACT: 16
|
||||
TEST_TYPE: test:node
|
||||
dist-react@15:
|
||||
REACT: 15
|
||||
TEST_TYPE: test:dist
|
||||
lib-react@15:
|
||||
REACT: 15
|
||||
TEST_TYPE: test:lib
|
||||
es-react@15:
|
||||
REACT: 15
|
||||
TEST_TYPE: test:es
|
||||
dom-react@15:
|
||||
REACT: 15
|
||||
TEST_TYPE: test:dom
|
||||
node-react@15:
|
||||
REACT: 15
|
||||
TEST_TYPE: test:node
|
||||
steps:
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
clean: false
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '11.x'
|
||||
- script: npm install
|
||||
displayName: install
|
||||
- script: scripts/install-react.sh
|
||||
displayName: install-react
|
||||
- script: scripts/travis-script.sh
|
||||
displayName: test
|
||||
- task: PublishBuildArtifacts@1
|
||||
# 主分支,并且运行成功
|
||||
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
inputs:
|
||||
pathtoPublish: './package-lock.json'
|
||||
artifactName: lock
|
||||
@@ -18,24 +18,17 @@ Array [
|
||||
"Cascader",
|
||||
"Checkbox",
|
||||
"Col",
|
||||
"Comment",
|
||||
"ConfigProvider",
|
||||
"DatePicker",
|
||||
"Divider",
|
||||
"Dropdown",
|
||||
"Drawer",
|
||||
"Empty",
|
||||
"Form",
|
||||
"Icon",
|
||||
"Input",
|
||||
"InputNumber",
|
||||
"Layout",
|
||||
"List",
|
||||
"LocaleProvider",
|
||||
"message",
|
||||
"Menu",
|
||||
"Modal",
|
||||
"Statistic",
|
||||
"notification",
|
||||
"Pagination",
|
||||
"Popconfirm",
|
||||
@@ -45,7 +38,6 @@ Array [
|
||||
"Rate",
|
||||
"Row",
|
||||
"Select",
|
||||
"Skeleton",
|
||||
"Slider",
|
||||
"Spin",
|
||||
"Steps",
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
const OLD_NODE_ENV = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = 'development';
|
||||
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
const antd = require('..');
|
||||
import * as antd from '..';
|
||||
|
||||
describe('antd', () => {
|
||||
afterAll(() => {
|
||||
process.env.NODE_ENV = OLD_NODE_ENV;
|
||||
});
|
||||
|
||||
it('exports modules correctly', () => {
|
||||
expect(Object.keys(antd)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should hint when import all components in dev mode', () => {
|
||||
expect(warnSpy).toBeCalledWith(
|
||||
'You are using a whole package of antd, please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.',
|
||||
);
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import raf from 'raf';
|
||||
import delayRaf from '../raf';
|
||||
import throttleByAnimationFrame from '../throttleByAnimationFrame';
|
||||
import getDataOrAriaProps from '../getDataOrAriaProps';
|
||||
import triggerEvent from '../triggerEvent';
|
||||
|
||||
describe('Test utils function', () => {
|
||||
beforeAll(() => {
|
||||
@@ -36,96 +32,4 @@ describe('Test utils function', () => {
|
||||
jest.runAllTimers();
|
||||
expect(callback).not.toBeCalled();
|
||||
});
|
||||
|
||||
describe('getDataOrAriaProps', () => {
|
||||
it('returns all data-* properties from an object', () => {
|
||||
const props = {
|
||||
onClick: () => {},
|
||||
isOpen: true,
|
||||
'data-test': 'test-id',
|
||||
'data-id': 1234,
|
||||
};
|
||||
const results = getDataOrAriaProps(props);
|
||||
expect(results).toEqual({
|
||||
'data-test': 'test-id',
|
||||
'data-id': 1234,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not return data-__ properties from an object', () => {
|
||||
const props = {
|
||||
onClick: () => {},
|
||||
isOpen: true,
|
||||
'data-__test': 'test-id',
|
||||
'data-__id': 1234,
|
||||
};
|
||||
const results = getDataOrAriaProps(props);
|
||||
expect(results).toEqual({});
|
||||
});
|
||||
|
||||
it('returns all aria-* properties from an object', () => {
|
||||
const props = {
|
||||
onClick: () => {},
|
||||
isOpen: true,
|
||||
'aria-labelledby': 'label-id',
|
||||
'aria-label': 'some-label',
|
||||
};
|
||||
const results = getDataOrAriaProps(props);
|
||||
expect(results).toEqual({
|
||||
'aria-labelledby': 'label-id',
|
||||
'aria-label': 'some-label',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns role property from an object', () => {
|
||||
const props = {
|
||||
onClick: () => {},
|
||||
isOpen: true,
|
||||
role: 'search',
|
||||
};
|
||||
const results = getDataOrAriaProps(props);
|
||||
expect(results).toEqual({ role: 'search' });
|
||||
});
|
||||
});
|
||||
|
||||
it('delayRaf', done => {
|
||||
jest.useRealTimers();
|
||||
|
||||
let bamboo = false;
|
||||
delayRaf(() => {
|
||||
bamboo = true;
|
||||
}, 3);
|
||||
|
||||
// Variable bamboo should be false in frame 2 but true in frame 4
|
||||
raf(() => {
|
||||
expect(bamboo).toBe(false);
|
||||
|
||||
// Frame 2
|
||||
raf(() => {
|
||||
expect(bamboo).toBe(false);
|
||||
|
||||
// Frame 3
|
||||
raf(() => {
|
||||
// Frame 4
|
||||
raf(() => {
|
||||
expect(bamboo).toBe(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('triggerEvent', () => {
|
||||
const button = document.createElement('button');
|
||||
button.addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
button.style.width = '100px';
|
||||
},
|
||||
true,
|
||||
);
|
||||
triggerEvent(button, 'click');
|
||||
expect(button.style.width).toBe('100px');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
export default function getDataOrAriaProps(props: any) {
|
||||
return Object.keys(props).reduce((prev: any, key: string) => {
|
||||
if (
|
||||
(key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-' || key === 'role') &&
|
||||
key.substr(0, 7) !== 'data-__'
|
||||
) {
|
||||
prev[key] = props[key];
|
||||
}
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
30
components/_util/getLocale.tsx
Normal file
30
components/_util/getLocale.tsx
Normal 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;
|
||||
}
|
||||
44
components/_util/getRequestAnimationFrame.tsx
Normal file
44
components/_util/getRequestAnimationFrame.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
const availablePrefixs = ['moz', 'ms', 'webkit'];
|
||||
|
||||
function requestAnimationFramePolyfill() {
|
||||
let lastTime = 0;
|
||||
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);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
}
|
||||
|
||||
export default function getRequestAnimationFrame() {
|
||||
if (typeof window === 'undefined') {
|
||||
return () => {};
|
||||
}
|
||||
if (window.requestAnimationFrame) {
|
||||
// https://github.com/vuejs/vue/issues/4465
|
||||
return window.requestAnimationFrame.bind(window);
|
||||
}
|
||||
|
||||
const prefix = availablePrefixs.filter(key => `${key}RequestAnimationFrame` in window)[0];
|
||||
|
||||
return prefix
|
||||
? window[`${prefix}RequestAnimationFrame`]
|
||||
: requestAnimationFramePolyfill();
|
||||
}
|
||||
|
||||
export function cancelRequestAnimationFrame(id) {
|
||||
if (typeof window === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
if (window.cancelAnimationFrame) {
|
||||
return window.cancelAnimationFrame(id);
|
||||
}
|
||||
const prefix = availablePrefixs.filter(key =>
|
||||
`${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window,
|
||||
)[0];
|
||||
|
||||
return prefix ?
|
||||
(window[`${prefix}CancelAnimationFrame`] || window[`${prefix}CancelRequestAnimationFrame`]).call(this, id)
|
||||
: clearTimeout(id);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export default function getScroll(target: HTMLElement | Window | null, top: boolean): number {
|
||||
export default function getScroll(target, top): number {
|
||||
if (typeof window === 'undefined') {
|
||||
return 0;
|
||||
}
|
||||
@@ -7,10 +7,10 @@ export default function getScroll(target: HTMLElement | Window | null, top: bool
|
||||
const method = top ? 'scrollTop' : 'scrollLeft';
|
||||
const isWindow = target === window;
|
||||
|
||||
let ret = isWindow ? (target as Window)[prop] : (target as HTMLElement)[method];
|
||||
let ret = isWindow ? target[prop] : target[method];
|
||||
// ie6,7,8 standard mode
|
||||
if (isWindow && typeof ret !== 'number') {
|
||||
ret = (document.documentElement as HTMLElement)[method];
|
||||
ret = window.document.documentElement[method];
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
// https://github.com/moment/moment/issues/3650
|
||||
export default function interopDefault(m: any) {
|
||||
return m.default || m;
|
||||
}
|
||||
24
components/_util/isCssAnimationSupported.tsx
Normal file
24
components/_util/isCssAnimationSupported.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
let animation;
|
||||
|
||||
function isCssAnimationSupported() {
|
||||
if (animation !== undefined) {
|
||||
return animation;
|
||||
}
|
||||
const domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
|
||||
const elm = document.createElement('div');
|
||||
if (elm.style.animationName !== undefined) {
|
||||
animation = true;
|
||||
}
|
||||
if (animation !== undefined) {
|
||||
for (let i = 0; i < domPrefixes.length; i++) {
|
||||
if (elm.style[`${domPrefixes[i]}AnimationName`] !== undefined) {
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
animation = animation || false;
|
||||
return animation;
|
||||
}
|
||||
|
||||
export default isCssAnimationSupported;
|
||||
10
components/_util/isFlexSupported.tsx
Normal file
10
components/_util/isFlexSupported.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function isFlexSupported() {
|
||||
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
|
||||
const { documentElement } = window.document;
|
||||
return 'flex' in documentElement.style ||
|
||||
'webkitFlex' in documentElement.style ||
|
||||
'Flex' in documentElement.style ||
|
||||
'msFlex' in documentElement.style;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
const isNumeric = (value: any): boolean => {
|
||||
return !isNaN(parseFloat(value)) && isFinite(value);
|
||||
};
|
||||
|
||||
export default isNumeric;
|
||||
@@ -1,32 +1,34 @@
|
||||
import cssAnimation from 'css-animation';
|
||||
import raf from 'raf';
|
||||
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from './getRequestAnimationFrame';
|
||||
|
||||
function animate(node: HTMLElement, show: boolean, done: () => void) {
|
||||
let height: number;
|
||||
let requestAnimationFrameId: number;
|
||||
const reqAnimFrame = getRequestAnimationFrame();
|
||||
|
||||
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() {
|
||||
if (requestAnimationFrameId) {
|
||||
raf.cancel(requestAnimationFrameId);
|
||||
cancelRequestAnimationFrame(requestAnimationFrameId);
|
||||
}
|
||||
requestAnimationFrameId = raf(() => {
|
||||
requestAnimationFrameId = reqAnimFrame(() => {
|
||||
node.style.height = `${show ? height : 0}px`;
|
||||
node.style.opacity = show ? '1' : '0';
|
||||
node.style.opacity = show ? 1 : 0;
|
||||
});
|
||||
},
|
||||
end() {
|
||||
if (requestAnimationFrameId) {
|
||||
raf.cancel(requestAnimationFrameId);
|
||||
cancelRequestAnimationFrame(requestAnimationFrameId);
|
||||
}
|
||||
node.style.height = '';
|
||||
node.style.opacity = '';
|
||||
@@ -36,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);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import raf from 'raf';
|
||||
|
||||
interface RafMap {
|
||||
[id: number]: number;
|
||||
}
|
||||
|
||||
let id: number = 0;
|
||||
const ids: RafMap = {};
|
||||
|
||||
// Support call raf with delay specified frame
|
||||
export default function wrapperRaf(callback: () => void, delayFrames: number = 1): number {
|
||||
const myId: number = id++;
|
||||
let restFrames: number = delayFrames;
|
||||
|
||||
function internalCallback() {
|
||||
restFrames -= 1;
|
||||
|
||||
if (restFrames <= 0) {
|
||||
callback();
|
||||
delete ids[id];
|
||||
} else {
|
||||
ids[id] = raf(internalCallback);
|
||||
}
|
||||
}
|
||||
|
||||
ids[id] = raf(internalCallback);
|
||||
|
||||
return myId;
|
||||
}
|
||||
|
||||
wrapperRaf.cancel = function(pid: number) {
|
||||
raf.cancel(ids[pid]);
|
||||
delete ids[pid];
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
function isStyleSupport(styleName: string | Array<string>): boolean {
|
||||
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
|
||||
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
|
||||
const { documentElement } = window.document;
|
||||
|
||||
return styleNameList.some(name => name in documentElement.style);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export const isFlexSupported = isStyleSupport(['flex', 'webkitFlex', 'Flex', 'msFlex']);
|
||||
|
||||
export default isStyleSupport;
|
||||
@@ -1,27 +1,29 @@
|
||||
import raf from 'raf';
|
||||
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from '../_util/getRequestAnimationFrame';
|
||||
|
||||
export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
|
||||
let requestId: number | null;
|
||||
const reqAnimFrame = getRequestAnimationFrame();
|
||||
|
||||
const later = (args: any[]) => () => {
|
||||
export default function throttleByAnimationFrame(fn) {
|
||||
let requestId;
|
||||
|
||||
const later = args => () => {
|
||||
requestId = null;
|
||||
fn(...args);
|
||||
};
|
||||
|
||||
const throttled = (...args: any[]) => {
|
||||
const throttled = (...args) => {
|
||||
if (requestId == null) {
|
||||
requestId = raf(later(args));
|
||||
requestId = reqAnimFrame(later(args));
|
||||
}
|
||||
};
|
||||
|
||||
(throttled as any).cancel = () => raf.cancel(requestId!);
|
||||
(throttled as any).cancel = () => cancelRequestAnimationFrame(requestId);
|
||||
|
||||
return throttled;
|
||||
}
|
||||
|
||||
export function throttleByAnimationFrameDecorator() {
|
||||
return function(target: any, key: string, descriptor: any) {
|
||||
const fn = descriptor.value;
|
||||
return function(target, key, descriptor) {
|
||||
let fn = descriptor.value;
|
||||
let definingProperty = false;
|
||||
return {
|
||||
configurable: true,
|
||||
@@ -30,7 +32,7 @@ export function throttleByAnimationFrameDecorator() {
|
||||
return fn;
|
||||
}
|
||||
|
||||
const boundFn = throttleByAnimationFrame(fn.bind(this));
|
||||
let boundFn = throttleByAnimationFrame(fn.bind(this));
|
||||
definingProperty = true;
|
||||
Object.defineProperty(this, key, {
|
||||
value: boundFn,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
// https://stackoverflow.com/questions/46176165/ways-to-get-string-literal-type-of-array-values-without-enum-overhead
|
||||
export const tuple = <T extends string[]>(...args: T) => args;
|
||||
@@ -1,6 +1,6 @@
|
||||
import warning from 'warning';
|
||||
|
||||
const warned: Record<string, boolean> = {};
|
||||
const warned: { [msg: string]: boolean} = {};
|
||||
export default (valid: boolean, message: string): void => {
|
||||
if (!valid && !warned[message]) {
|
||||
warning(false, message);
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import TransitionEvents from 'css-animation/lib/Event';
|
||||
import raf from '../_util/raf';
|
||||
import { ConfigConsumer, ConfigConsumerProps, CSPConfig } from '../config-provider';
|
||||
|
||||
let styleForPesudo: HTMLStyleElement | null;
|
||||
|
||||
// Where el is the DOM element you'd like to test for visibility
|
||||
function isHidden(element: HTMLElement) {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return false;
|
||||
}
|
||||
return !element || element.offsetParent === null;
|
||||
}
|
||||
|
||||
export default class Wave extends React.Component<{ insertExtraNode?: boolean }> {
|
||||
private instance?: {
|
||||
cancel: () => void;
|
||||
};
|
||||
|
||||
private extraNode: HTMLDivElement;
|
||||
private clickWaveTimeoutId: number;
|
||||
private animationStartId: number;
|
||||
private animationStart: boolean = false;
|
||||
private destroy: boolean = false;
|
||||
private csp?: CSPConfig;
|
||||
|
||||
isNotGrey(color: string) {
|
||||
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/);
|
||||
if (match && match[1] && match[2] && match[3]) {
|
||||
return !(match[1] === match[2] && match[2] === match[3]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
onClick = (node: HTMLElement, waveColor: string) => {
|
||||
if (!node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
|
||||
return;
|
||||
}
|
||||
const { insertExtraNode } = this.props;
|
||||
this.extraNode = document.createElement('div');
|
||||
const extraNode = this.extraNode;
|
||||
extraNode.className = 'ant-click-animating-node';
|
||||
const attributeName = this.getAttributeName();
|
||||
node.setAttribute(attributeName, 'true');
|
||||
// Not white or transparnt or grey
|
||||
styleForPesudo = styleForPesudo || document.createElement('style');
|
||||
if (
|
||||
waveColor &&
|
||||
waveColor !== '#ffffff' &&
|
||||
waveColor !== 'rgb(255, 255, 255)' &&
|
||||
this.isNotGrey(waveColor) &&
|
||||
!/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color
|
||||
waveColor !== 'transparent'
|
||||
) {
|
||||
// Add nonce if CSP exist
|
||||
if (this.csp && this.csp.nonce) {
|
||||
styleForPesudo.nonce = this.csp.nonce;
|
||||
}
|
||||
|
||||
extraNode.style.borderColor = waveColor;
|
||||
styleForPesudo.innerHTML = `[ant-click-animating-without-extra-node="true"]:after { border-color: ${waveColor}; }`;
|
||||
if (!document.body.contains(styleForPesudo)) {
|
||||
document.body.appendChild(styleForPesudo);
|
||||
}
|
||||
}
|
||||
if (insertExtraNode) {
|
||||
node.appendChild(extraNode);
|
||||
}
|
||||
TransitionEvents.addStartEventListener(node, this.onTransitionStart);
|
||||
TransitionEvents.addEndEventListener(node, this.onTransitionEnd);
|
||||
};
|
||||
|
||||
bindAnimationEvent = (node: HTMLElement) => {
|
||||
if (
|
||||
!node ||
|
||||
!node.getAttribute ||
|
||||
node.getAttribute('disabled') ||
|
||||
node.className.indexOf('disabled') >= 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const onClick = (e: MouseEvent) => {
|
||||
// Fix radio button click twice
|
||||
if ((e.target as HTMLElement).tagName === 'INPUT' || isHidden(e.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
this.resetEffect(node);
|
||||
// Get wave color from target
|
||||
const waveColor =
|
||||
getComputedStyle(node).getPropertyValue('border-top-color') || // Firefox Compatible
|
||||
getComputedStyle(node).getPropertyValue('border-color') ||
|
||||
getComputedStyle(node).getPropertyValue('background-color');
|
||||
this.clickWaveTimeoutId = window.setTimeout(() => this.onClick(node, waveColor), 0);
|
||||
|
||||
raf.cancel(this.animationStartId);
|
||||
this.animationStart = true;
|
||||
|
||||
// Render to trigger transition event cost 3 frames. Let's delay 10 frames to reset this.
|
||||
this.animationStartId = raf(() => {
|
||||
this.animationStart = false;
|
||||
}, 10);
|
||||
};
|
||||
node.addEventListener('click', onClick, true);
|
||||
return {
|
||||
cancel: () => {
|
||||
node.removeEventListener('click', onClick, true);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
getAttributeName() {
|
||||
const { insertExtraNode } = this.props;
|
||||
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
|
||||
}
|
||||
|
||||
resetEffect(node: HTMLElement) {
|
||||
if (!node || node === this.extraNode || !(node instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
const { insertExtraNode } = this.props;
|
||||
const attributeName = this.getAttributeName();
|
||||
node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
|
||||
this.removeExtraStyleNode();
|
||||
if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
|
||||
node.removeChild(this.extraNode);
|
||||
}
|
||||
TransitionEvents.removeStartEventListener(node, this.onTransitionStart);
|
||||
TransitionEvents.removeEndEventListener(node, this.onTransitionEnd);
|
||||
}
|
||||
|
||||
onTransitionStart = (e: AnimationEvent) => {
|
||||
if (this.destroy) return;
|
||||
|
||||
const node = findDOMNode(this) as HTMLElement;
|
||||
if (!e || e.target !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.animationStart) {
|
||||
this.resetEffect(node);
|
||||
}
|
||||
};
|
||||
|
||||
onTransitionEnd = (e: AnimationEvent) => {
|
||||
if (!e || e.animationName !== 'fadeEffect') {
|
||||
return;
|
||||
}
|
||||
this.resetEffect(e.target as HTMLElement);
|
||||
};
|
||||
|
||||
removeExtraStyleNode() {
|
||||
if (styleForPesudo) {
|
||||
styleForPesudo.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const node = findDOMNode(this) as HTMLElement;
|
||||
if (node.nodeType !== 1) {
|
||||
return;
|
||||
}
|
||||
this.instance = this.bindAnimationEvent(node);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.instance) {
|
||||
this.instance.cancel();
|
||||
}
|
||||
if (this.clickWaveTimeoutId) {
|
||||
clearTimeout(this.clickWaveTimeoutId);
|
||||
}
|
||||
|
||||
this.destroy = true;
|
||||
}
|
||||
|
||||
renderWave = ({ csp }: ConfigConsumerProps) => {
|
||||
const { children } = this.props;
|
||||
this.csp = csp;
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderWave}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,14 @@ const events = {};
|
||||
|
||||
class AffixMounter extends React.Component {
|
||||
componentDidMount() {
|
||||
this.container.scrollTop = 100;
|
||||
this.container.addEventListener = jest.fn().mockImplementation((event, cb) => {
|
||||
events[event] = cb;
|
||||
});
|
||||
}
|
||||
|
||||
getTarget = () => this.container;
|
||||
|
||||
getTarget = () => {
|
||||
return this.container;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
@@ -21,9 +22,7 @@ class AffixMounter extends React.Component {
|
||||
height: 100,
|
||||
overflowY: 'scroll',
|
||||
}}
|
||||
ref={node => {
|
||||
this.container = node;
|
||||
}}
|
||||
ref={(node) => { this.container = node; }}
|
||||
>
|
||||
<div
|
||||
className="background"
|
||||
@@ -34,12 +33,11 @@ class AffixMounter extends React.Component {
|
||||
>
|
||||
<Affix
|
||||
target={() => this.container}
|
||||
ref={ele => {
|
||||
this.affix = ele;
|
||||
}}
|
||||
{...this.props}
|
||||
ref={ele => this.affix = ele}
|
||||
>
|
||||
<Button type="primary">Fixed at the top of container</Button>
|
||||
<Button type="primary" >
|
||||
Fixed at the top of container
|
||||
</Button>
|
||||
</Affix>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,8 +46,6 @@ class AffixMounter extends React.Component {
|
||||
}
|
||||
|
||||
describe('Affix Render', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
@@ -58,70 +54,23 @@ describe('Affix Render', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
const scrollTo = top => {
|
||||
wrapper.instance().affix.fixedNode.parentNode.getBoundingClientRect = jest.fn(() => ({
|
||||
bottom: 100,
|
||||
height: 28,
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 50 - top,
|
||||
width: 195,
|
||||
}));
|
||||
wrapper.instance().container.scrollTop = top;
|
||||
events.scroll({
|
||||
type: 'scroll',
|
||||
});
|
||||
jest.runAllTimers();
|
||||
};
|
||||
|
||||
it('Anchor render perfectly', () => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
|
||||
wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
|
||||
const wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
|
||||
jest.runAllTimers();
|
||||
|
||||
scrollTo(0);
|
||||
expect(wrapper.instance().affix.state.affixStyle).toBe(null);
|
||||
|
||||
scrollTo(100);
|
||||
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
|
||||
|
||||
scrollTo(0);
|
||||
expect(wrapper.instance().affix.state.affixStyle).toBe(null);
|
||||
});
|
||||
|
||||
it('support offsetBottom', () => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
|
||||
wrapper = mount(<AffixMounter offsetBottom={0} />, {
|
||||
attachTo: document.getElementById('mounter'),
|
||||
wrapper.node.affix.refs.fixedNode.parentNode.getBoundingClientRect = jest.fn(() => {
|
||||
return {
|
||||
bottom: 100, height: 28, left: 0, right: 0, top: -50, width: 195,
|
||||
};
|
||||
});
|
||||
jest.runAllTimers();
|
||||
|
||||
scrollTo(0);
|
||||
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
|
||||
|
||||
scrollTo(100);
|
||||
expect(wrapper.instance().affix.state.affixStyle).toBe(null);
|
||||
|
||||
scrollTo(0);
|
||||
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
|
||||
});
|
||||
|
||||
it('updatePosition when offsetTop changed', () => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
|
||||
wrapper = mount(<AffixMounter offsetTop={0} />, {
|
||||
attachTo: document.getElementById('mounter'),
|
||||
events.scroll({
|
||||
type: 'scroll',
|
||||
});
|
||||
jest.runAllTimers();
|
||||
|
||||
scrollTo(100);
|
||||
expect(wrapper.instance().affix.state.affixStyle.top).toBe(0);
|
||||
wrapper.setProps({
|
||||
offsetTop: 10,
|
||||
});
|
||||
jest.runAllTimers();
|
||||
expect(wrapper.instance().affix.state.affixStyle.top).toBe(10);
|
||||
expect(wrapper.node.affix.state.affixStyle).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,44 +16,16 @@ The simplest usage.
|
||||
````jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
top: 10,
|
||||
bottom: 10,
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Affix offsetTop={this.state.top}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
top: this.state.top + 10,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Affix top
|
||||
</Button>
|
||||
</Affix>
|
||||
<br />
|
||||
<Affix offsetBottom={this.state.bottom}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
bottom: this.state.bottom + 10,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Affix bottom
|
||||
</Button>
|
||||
</Affix>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Affix>
|
||||
<Button type="primary">Affix top</Button>
|
||||
</Affix>
|
||||
<br />
|
||||
<Affix offsetBottom={0}>
|
||||
<Button type="primary">Affix bottom</Button>
|
||||
</Affix>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
````
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import * as PropTypes from 'prop-types';
|
||||
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';
|
||||
import shallowequal from 'shallowequal';
|
||||
import omit from 'omit.js';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
|
||||
|
||||
function getTargetRect(target: HTMLElement | Window | null): ClientRect {
|
||||
return target !== window
|
||||
? (target as HTMLElement).getBoundingClientRect()
|
||||
: ({ top: 0, left: 0, bottom: 0 } as ClientRect);
|
||||
function getTargetRect(target): ClientRect {
|
||||
return target !== window ?
|
||||
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);
|
||||
|
||||
@@ -27,8 +26,10 @@ function getOffset(element: HTMLElement, target: HTMLElement | Window | null) {
|
||||
const clientLeft = docElem.clientLeft || 0;
|
||||
|
||||
return {
|
||||
top: elemRect.top - targetRect.top + scrollTop - clientTop,
|
||||
left: elemRect.left - targetRect.left + scrollLeft - clientLeft,
|
||||
top: elemRect.top - targetRect.top +
|
||||
scrollTop - clientTop,
|
||||
left: elemRect.left - targetRect.left +
|
||||
scrollLeft - clientLeft,
|
||||
width: elemRect.width,
|
||||
height: elemRect.height,
|
||||
};
|
||||
@@ -37,7 +38,8 @@ function getOffset(element: HTMLElement, target: HTMLElement | Window | null) {
|
||||
function noop() {}
|
||||
|
||||
function getDefaultTarget() {
|
||||
return typeof window !== 'undefined' ? window : null;
|
||||
return typeof window !== 'undefined' ?
|
||||
window : null;
|
||||
}
|
||||
|
||||
// Affix
|
||||
@@ -53,33 +55,25 @@ export interface AffixProps {
|
||||
/** 固定状态改变时触发的回调函数 */
|
||||
onChange?: (affixed?: boolean) => void;
|
||||
/** 设置 Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
|
||||
target?: () => Window | HTMLElement | null;
|
||||
target?: () => Window | HTMLElement;
|
||||
prefixCls?: string;
|
||||
className?: 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,
|
||||
target: PropTypes.func,
|
||||
};
|
||||
|
||||
state: AffixState = {
|
||||
affixStyle: undefined,
|
||||
placeholderStyle: undefined,
|
||||
scrollEvent: any;
|
||||
resizeEvent: any;
|
||||
timeout: any;
|
||||
refs: {
|
||||
fixedNode: HTMLElement;
|
||||
};
|
||||
|
||||
private timeout: number;
|
||||
private eventHandlers: Record<string, any> = {};
|
||||
private fixedNode: HTMLElement;
|
||||
private placeholderNode: HTMLElement;
|
||||
private readonly events = [
|
||||
events = [
|
||||
'resize',
|
||||
'scroll',
|
||||
'touchstart',
|
||||
@@ -89,7 +83,17 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
'load',
|
||||
];
|
||||
|
||||
setAffixStyle(e: Event, affixStyle: React.CSSProperties | null) {
|
||||
eventHandlers = {};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
affixStyle: null,
|
||||
placeholderStyle: null,
|
||||
};
|
||||
}
|
||||
|
||||
setAffixStyle(e, affixStyle) {
|
||||
const { onChange = noop, target = getDefaultTarget } = this.props;
|
||||
const originalAffixStyle = this.state.affixStyle;
|
||||
const isWindow = target() === window;
|
||||
@@ -99,54 +103,36 @@ 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)) {
|
||||
if ((affixStyle && !originalAffixStyle) ||
|
||||
(!affixStyle && originalAffixStyle)) {
|
||||
onChange(affixed);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setPlaceholderStyle(placeholderStyle: React.CSSProperties | null) {
|
||||
setPlaceholderStyle(placeholderStyle) {
|
||||
const originalPlaceholderStyle = this.state.placeholderStyle;
|
||||
if (shallowequal(placeholderStyle, originalPlaceholderStyle)) {
|
||||
return;
|
||||
}
|
||||
this.setState({ placeholderStyle: placeholderStyle as React.CSSProperties });
|
||||
}
|
||||
|
||||
syncPlaceholderStyle(e: Event) {
|
||||
const { affixStyle } = this.state;
|
||||
if (!affixStyle) {
|
||||
return;
|
||||
}
|
||||
this.placeholderNode.style.cssText = '';
|
||||
this.setAffixStyle(e, {
|
||||
...affixStyle,
|
||||
width: this.placeholderNode.offsetWidth,
|
||||
});
|
||||
this.setPlaceholderStyle({
|
||||
width: this.placeholderNode.offsetWidth,
|
||||
});
|
||||
this.setState({ placeholderStyle });
|
||||
}
|
||||
|
||||
@throttleByAnimationFrameDecorator()
|
||||
updatePosition(e: Event) {
|
||||
const { offsetBottom, offset, target = getDefaultTarget } = this.props;
|
||||
let { offsetTop } = this.props;
|
||||
updatePosition(e) {
|
||||
let { offsetTop, offsetBottom, offset, target = getDefaultTarget } = this.props;
|
||||
const targetNode = target();
|
||||
|
||||
// Backwards support
|
||||
// Fix: if offsetTop === 0, it will get undefined,
|
||||
// if offsetBottom is type of number, offsetMode will be { top: false, ... }
|
||||
offsetTop = typeof offsetTop === 'undefined' ? offset : offsetTop;
|
||||
offsetTop = offsetTop || offset;
|
||||
const scrollTop = getScroll(targetNode, true);
|
||||
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 = {
|
||||
@@ -165,14 +151,12 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
const targetRect = getTargetRect(targetNode);
|
||||
const targetInnerHeight =
|
||||
(targetNode as Window).innerHeight || (targetNode as HTMLElement).clientHeight;
|
||||
// ref: https://github.com/ant-design/ant-design/issues/13662
|
||||
if (scrollTop >= elemOffset.top - (offsetTop as number) && offsetMode.top) {
|
||||
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,
|
||||
width,
|
||||
});
|
||||
@@ -181,12 +165,11 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
height: elemSize.height,
|
||||
});
|
||||
} else if (
|
||||
scrollTop <=
|
||||
elemOffset.top + elemSize.height + (offsetBottom as number) - targetInnerHeight &&
|
||||
offsetMode.bottom
|
||||
scrollTop < elemOffset.top + elemSize.height + (offsetBottom as number) - targetInnerHeight &&
|
||||
offsetMode.bottom
|
||||
) {
|
||||
// Fixed Bottom
|
||||
const targetBottomOffet = targetNode === window ? 0 : window.innerHeight - targetRect.bottom;
|
||||
const targetBottomOffet = targetNode === window ? 0 : (window.innerHeight - targetRect.bottom);
|
||||
const width = elemOffset.width;
|
||||
this.setAffixStyle(e, {
|
||||
position: 'fixed',
|
||||
@@ -200,22 +183,13 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
});
|
||||
} else {
|
||||
const { affixStyle } = this.state;
|
||||
if (
|
||||
e.type === 'resize' &&
|
||||
affixStyle &&
|
||||
affixStyle.position === 'fixed' &&
|
||||
affixNode.offsetWidth
|
||||
) {
|
||||
if (e.type === 'resize' && affixStyle && affixStyle.position === 'fixed' && affixNode.offsetWidth) {
|
||||
this.setAffixStyle(e, { ...affixStyle, width: affixNode.offsetWidth });
|
||||
} else {
|
||||
this.setAffixStyle(e, null);
|
||||
}
|
||||
this.setPlaceholderStyle(null);
|
||||
}
|
||||
|
||||
if (e.type === 'resize') {
|
||||
this.syncPlaceholderStyle(e);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -223,24 +197,16 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
// Wait for parent component ref has its value
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setTargetEventListeners(target);
|
||||
// Mock Event object.
|
||||
this.updatePosition({} as Event);
|
||||
});
|
||||
}
|
||||
|
||||
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({} as Event);
|
||||
}
|
||||
if (
|
||||
this.props.offsetTop !== nextProps.offsetTop ||
|
||||
this.props.offsetBottom !== nextProps.offsetBottom
|
||||
) {
|
||||
this.updatePosition({} as Event);
|
||||
this.updatePosition({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,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;
|
||||
@@ -271,38 +237,19 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
});
|
||||
}
|
||||
|
||||
saveFixedNode = (node: HTMLDivElement) => {
|
||||
this.fixedNode = node;
|
||||
};
|
||||
|
||||
savePlaceholderNode = (node: HTMLDivElement) => {
|
||||
this.placeholderNode = node;
|
||||
};
|
||||
|
||||
renderAffix = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls } = this.props;
|
||||
render() {
|
||||
const className = classNames({
|
||||
[getPrefixCls('affix', prefixCls)]: this.state.affixStyle,
|
||||
[this.props.prefixCls || 'ant-affix']: this.state.affixStyle,
|
||||
});
|
||||
|
||||
const props = omit(this.props, [
|
||||
'prefixCls',
|
||||
'offsetTop',
|
||||
'offsetBottom',
|
||||
'target',
|
||||
'onChange',
|
||||
]);
|
||||
const props = omit(this.props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target', 'onChange']);
|
||||
const placeholderStyle = { ...this.state.placeholderStyle, ...this.props.style };
|
||||
return (
|
||||
<div {...props} style={placeholderStyle} ref={this.savePlaceholderNode}>
|
||||
<div className={className} ref={this.saveFixedNode} style={this.state.affixStyle}>
|
||||
<div {...props} style={placeholderStyle}>
|
||||
<div className={className} ref="fixedNode" style={this.state.affixStyle}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAffix}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 固钉
|
||||
type: 导航
|
||||
type: Navigation
|
||||
title: Affix
|
||||
---
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../style/themes/default';
|
||||
@import "../../style/themes/default";
|
||||
|
||||
.@{ant-prefix}-affix {
|
||||
position: fixed;
|
||||
|
||||
@@ -7,23 +7,8 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -35,27 +20,12 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-banner ant-alert-closable"
|
||||
class="ant-alert ant-alert-warning ant-alert-banner"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -68,23 +38,8 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-cross"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<br />
|
||||
@@ -107,23 +62,8 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close-circle"
|
||||
class="anticon anticon-close-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-cross-circle ant-alert-icon"
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -155,7 +95,7 @@ exports[`renders ./components/alert/demo/basic.md correctly 1`] = `
|
||||
exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-closable"
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
@@ -170,27 +110,12 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-cross"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
|
||||
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
@@ -207,23 +132,8 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-cross"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -231,7 +141,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
|
||||
exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon ant-alert-closable"
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
@@ -250,280 +160,6 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/custom-icon.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
showIcon = false
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-success"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Success Tips
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-info"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Informational Notes
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-with-description"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Success Tips
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Detailed description and advices about successful copywriting.
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-with-description"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Informational Notes
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Additional description and informations about copywriting.
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-with-description"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
This is a warning notice about copywriting.
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-with-description"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: smile"
|
||||
class="anticon anticon-smile ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
This is an error message about copywriting.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/description.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
@@ -596,23 +232,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: check-circle"
|
||||
class="anticon anticon-check-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 0 1-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -627,23 +248,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: info-circle"
|
||||
class="anticon anticon-info-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="info-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -658,23 +264,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -689,23 +280,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close-circle"
|
||||
class="anticon anticon-close-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-cross-circle ant-alert-icon"
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -720,30 +296,12 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: check-circle"
|
||||
class="anticon anticon-check-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M699 353h-46.9c-10.2 0-19.9 4.9-25.9 13.3L469 584.3l-71.2-98.8c-6-8.3-15.6-13.3-25.9-13.3H325c-6.5 0-10.3 7.4-6.5 12.7l124.6 172.8a31.8 31.8 0 0 0 51.7 0l210.6-292c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-check-circle-o ant-alert-icon"
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Success Tips
|
||||
success tips
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
@@ -756,26 +314,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: info-circle"
|
||||
class="anticon anticon-info-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="info-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
<path
|
||||
d="M464 336a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-info-circle-o ant-alert-icon"
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -792,26 +332,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
<path
|
||||
d="M464 688a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm24-112h48c4.4 0 8-3.6 8-8V296c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-exclamation-circle-o ant-alert-icon"
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -828,26 +350,8 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close-circle"
|
||||
class="anticon anticon-close-circle ant-alert-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M685.4 354.8c0-4.4-3.6-8-8-8l-66 .3L512 465.6l-99.3-118.4-66.1-.3c-4.4 0-8 3.5-8 8 0 1.9.7 3.7 1.9 5.2l130.1 155L340.5 670a8.32 8.32 0 0 0-1.9 5.2c0 4.4 3.6 8 8 8l66.1-.3L512 564.4l99.3 118.4 66 .3c4.4 0 8-3.5 8-8 0-1.9-.7-3.7-1.9-5.2L553.5 515l130.1-155c1.2-1.4 1.8-3.3 1.8-5.2z"
|
||||
/>
|
||||
<path
|
||||
d="M512 65C264.6 65 64 265.6 64 513s200.6 448 448 448 448-200.6 448-448S759.4 65 512 65zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
class="anticon anticon-cross-circle-o ant-alert-icon"
|
||||
/>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
@@ -862,49 +366,6 @@ exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon ant-alert-closable"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Alert Message Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<a
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</a>
|
||||
</div>
|
||||
<p>
|
||||
placeholder text here
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/style.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Alert from '..';
|
||||
|
||||
describe('Alert', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('could be closed', () => {
|
||||
const onClose = jest.fn();
|
||||
const afterClose = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Alert
|
||||
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
|
||||
type="warning"
|
||||
closable
|
||||
onClose={onClose}
|
||||
afterClose={afterClose}
|
||||
/>,
|
||||
);
|
||||
wrapper.find('.ant-alert-close-icon').simulate('click');
|
||||
expect(onClose).toBeCalled();
|
||||
jest.runAllTimers();
|
||||
expect(afterClose).toBeCalled();
|
||||
});
|
||||
|
||||
describe('data and aria props', () => {
|
||||
it('sets data attributes on input', () => {
|
||||
const wrapper = mount(<Alert data-test="test-id" data-id="12345" />);
|
||||
const input = wrapper.find('.ant-alert').getDOMNode();
|
||||
expect(input.getAttribute('data-test')).toBe('test-id');
|
||||
expect(input.getAttribute('data-id')).toBe('12345');
|
||||
});
|
||||
|
||||
it('sets aria attributes on input', () => {
|
||||
const wrapper = mount(<Alert aria-describedby="some-label" />);
|
||||
const input = wrapper.find('.ant-alert').getDOMNode();
|
||||
expect(input.getAttribute('aria-describedby')).toBe('some-label');
|
||||
});
|
||||
|
||||
it('sets role attribute on input', () => {
|
||||
const wrapper = mount(<Alert role="status" />);
|
||||
const input = wrapper.find('.ant-alert').getDOMNode();
|
||||
expect(input.getAttribute('role')).toBe('status');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -26,7 +26,6 @@ ReactDOM.render(
|
||||
<Alert showIcon={false} message="Warning text without icon" banner />
|
||||
<br />
|
||||
<Alert type="error" message="Error text" banner />
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -17,9 +17,8 @@ The simplest usage for short messages.
|
||||
import { Alert } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<Alert message="Success Text" type="success" />,
|
||||
mountNode
|
||||
);
|
||||
<Alert message="Success Text" type="success" />
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
<style>
|
||||
|
||||
@@ -16,7 +16,7 @@ To show close button.
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
|
||||
const onClose = (e) => {
|
||||
const onClose = function (e) {
|
||||
console.log(e, 'I was closed.');
|
||||
};
|
||||
|
||||
@@ -35,7 +35,6 @@ ReactDOM.render(
|
||||
closable
|
||||
onClose={onClose}
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -17,7 +17,6 @@ Replace the default icon with customized text.
|
||||
import { Alert } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<Alert message="Info Text" type="info" closeText="Close Now" />,
|
||||
mountNode
|
||||
);
|
||||
<Alert message="Info Text" type="info" closeText="Close Now" />
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
order: 12
|
||||
debug: true
|
||||
title:
|
||||
zh-CN: 自定义图标
|
||||
en-US: Custom Icon
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
可口的图标让信息类型更加醒目。
|
||||
|
||||
## en-US
|
||||
|
||||
Decent icon make information more clear and more friendly.
|
||||
|
||||
````jsx
|
||||
import { Alert, Icon } from 'antd';
|
||||
|
||||
const icon = <Icon type="smile" />;
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Alert icon={icon} message="showIcon = false" type="success" />
|
||||
<Alert icon={icon} message="Success Tips" type="success" showIcon />
|
||||
<Alert icon={icon} message="Informational Notes" type="info" showIcon />
|
||||
<Alert icon={icon} message="Warning" type="warning" showIcon />
|
||||
<Alert icon={icon} message="Error" type="error" showIcon />
|
||||
<Alert
|
||||
icon={icon}
|
||||
message="Success Tips"
|
||||
description="Detailed description and advices about successful copywriting."
|
||||
type="success"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
icon={icon}
|
||||
message="Informational Notes"
|
||||
description="Additional description and informations about copywriting."
|
||||
type="info"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
icon={icon}
|
||||
message="Warning"
|
||||
description="This is a warning notice about copywriting."
|
||||
type="warning"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
icon={icon}
|
||||
message="Error"
|
||||
description="This is an error message about copywriting."
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
````
|
||||
@@ -38,7 +38,6 @@ ReactDOM.render(
|
||||
description="Error Description Error Description Error Description Error Description"
|
||||
type="error"
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -23,7 +23,7 @@ ReactDOM.render(
|
||||
<Alert message="Warning" type="warning" showIcon />
|
||||
<Alert message="Error" type="error" showIcon />
|
||||
<Alert
|
||||
message="Success Tips"
|
||||
message="success tips"
|
||||
description="Detailed description and advices about successful copywriting."
|
||||
type="success"
|
||||
showIcon
|
||||
@@ -46,7 +46,6 @@ ReactDOM.render(
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
order: 7
|
||||
title:
|
||||
zh-CN: 平滑地卸载
|
||||
en-US: Smoothly Unmount
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
平滑、自然的卸载提示。
|
||||
|
||||
## en-US
|
||||
|
||||
Smoothly and unaffectedly unmount Alert.
|
||||
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
visible: true,
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ visible: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.visible ? (
|
||||
<Alert
|
||||
message="Alert Message Text"
|
||||
type="success"
|
||||
closable
|
||||
afterClose={this.handleClose}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
<p>placeholder text here</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<App />,
|
||||
mountNode
|
||||
);
|
||||
````
|
||||
@@ -22,7 +22,6 @@ ReactDOM.render(
|
||||
<Alert message="Info Text" type="info" />
|
||||
<Alert message="Warning Text" type="warning" />
|
||||
<Alert message="Error Text" type="error" />
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -15,13 +15,11 @@ Alert component for feedback.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| afterClose | Called when close animation is finished | () => void | - |
|
||||
| banner | Whether to show as banner | boolean | false |
|
||||
| closable | Whether Alert can be closed | boolean | - |
|
||||
| closeText | Close text to show | string\|ReactNode | - |
|
||||
| description | Additional content of Alert | string\|ReactNode | - |
|
||||
| icon | Custom icon, effective when `showIcon` is `true` | ReactNode | - |
|
||||
| message | Content of Alert | string\|ReactNode | - |
|
||||
| showIcon | Whether to show icon | boolean | false, in `banner` mode default is true |
|
||||
| type | Type of Alert styles, options: `success`, `info`, `warning`, `error` | string | `info`, in `banner` mode default is `warning` |
|
||||
| onClose | Callback when Alert is closed | (e: MouseEvent) => void | - |
|
||||
| onClose | Callback when Alert is closed | Function | - |
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
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, { ThemeType } from '../icon';
|
||||
import Icon from '../icon';
|
||||
import classNames from 'classnames';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import getDataOrAriaProps from '../_util/getDataOrAriaProps';
|
||||
|
||||
function noop() {}
|
||||
function noop() { }
|
||||
|
||||
export interface AlertProps {
|
||||
/**
|
||||
@@ -23,32 +21,25 @@ export interface AlertProps {
|
||||
description?: React.ReactNode;
|
||||
/** Callback when close Alert */
|
||||
onClose?: React.MouseEventHandler<HTMLAnchorElement>;
|
||||
/** Trigger when animation ending of Alert */
|
||||
afterClose?: () => void;
|
||||
/** Whether to show icon */
|
||||
showIcon?: boolean;
|
||||
iconType?: string;
|
||||
style?: React.CSSProperties;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
banner?: boolean;
|
||||
icon?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface AlertState {
|
||||
closing: boolean;
|
||||
closed: boolean;
|
||||
}
|
||||
|
||||
export default class Alert extends React.Component<AlertProps, AlertState> {
|
||||
state: AlertState = {
|
||||
closing: true,
|
||||
closed: false,
|
||||
};
|
||||
|
||||
export default class Alert extends React.Component<AlertProps, any> {
|
||||
constructor(props: AlertProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
closing: true,
|
||||
closed: false,
|
||||
};
|
||||
}
|
||||
handleClose = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault();
|
||||
const dom = ReactDOM.findDOMNode(this) as HTMLElement;
|
||||
let dom = ReactDOM.findDOMNode(this) as HTMLElement;
|
||||
dom.style.height = `${dom.offsetHeight}px`;
|
||||
// Magic code
|
||||
// 重复一次后才能正确设置 height
|
||||
@@ -58,101 +49,66 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
||||
closing: false,
|
||||
});
|
||||
(this.props.onClose || noop)(e);
|
||||
};
|
||||
|
||||
}
|
||||
animationEnd = () => {
|
||||
this.setState({
|
||||
closed: true,
|
||||
closing: true,
|
||||
});
|
||||
(this.props.afterClose || noop)();
|
||||
};
|
||||
|
||||
renderAlert = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const {
|
||||
description,
|
||||
prefixCls: customizePrefixCls,
|
||||
message,
|
||||
closeText,
|
||||
banner,
|
||||
className = '',
|
||||
style,
|
||||
icon,
|
||||
}
|
||||
render() {
|
||||
let {
|
||||
closable, description, type, prefixCls = 'ant-alert', message, closeText, showIcon, banner,
|
||||
className = '', style,
|
||||
} = this.props;
|
||||
let { closable, type, showIcon, iconType } = this.props;
|
||||
|
||||
const prefixCls = getPrefixCls('alert', customizePrefixCls);
|
||||
|
||||
// banner模式默认有 Icon
|
||||
showIcon = banner && showIcon === undefined ? true : showIcon;
|
||||
// banner模式默认为警告
|
||||
type = banner && type === undefined ? 'warning' : type || 'info';
|
||||
|
||||
let iconTheme: ThemeType = 'filled';
|
||||
// should we give a warning?
|
||||
// warning(!iconType, `The property 'iconType' is deprecated. Use the property 'icon' instead.`);
|
||||
if (!iconType) {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
iconType = 'check-circle';
|
||||
break;
|
||||
case 'info':
|
||||
iconType = 'info-circle';
|
||||
break;
|
||||
case 'error':
|
||||
iconType = 'close-circle';
|
||||
break;
|
||||
case 'warning':
|
||||
iconType = 'exclamation-circle';
|
||||
break;
|
||||
default:
|
||||
iconType = 'default';
|
||||
}
|
||||
|
||||
// use outline icon in alert with description
|
||||
if (!!description) {
|
||||
iconTheme = 'outlined';
|
||||
}
|
||||
let iconType = '';
|
||||
switch (type) {
|
||||
case 'success':
|
||||
iconType = 'check-circle';
|
||||
break;
|
||||
case 'info':
|
||||
iconType = 'info-circle';
|
||||
break;
|
||||
case 'error':
|
||||
iconType = 'cross-circle';
|
||||
break;
|
||||
case 'warning':
|
||||
iconType = 'exclamation-circle';
|
||||
break;
|
||||
default:
|
||||
iconType = 'default';
|
||||
}
|
||||
|
||||
// use outline icon in alert with description
|
||||
if (!!description) {
|
||||
iconType += '-o';
|
||||
}
|
||||
|
||||
let alertCls = classNames(prefixCls, {
|
||||
[`${prefixCls}-${type}`]: true,
|
||||
[`${prefixCls}-close`]: !this.state.closing,
|
||||
[`${prefixCls}-with-description`]: !!description,
|
||||
[`${prefixCls}-no-icon`]: !showIcon,
|
||||
[`${prefixCls}-banner`]: !!banner,
|
||||
}, className);
|
||||
|
||||
// closeable when closeText is assigned
|
||||
if (closeText) {
|
||||
closable = true;
|
||||
}
|
||||
|
||||
const alertCls = classNames(
|
||||
prefixCls,
|
||||
`${prefixCls}-${type}`,
|
||||
{
|
||||
[`${prefixCls}-close`]: !this.state.closing,
|
||||
[`${prefixCls}-with-description`]: !!description,
|
||||
[`${prefixCls}-no-icon`]: !showIcon,
|
||||
[`${prefixCls}-banner`]: !!banner,
|
||||
[`${prefixCls}-closable`]: closable,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
const closeIcon = closable ? (
|
||||
<a onClick={this.handleClose} className={`${prefixCls}-close-icon`}>
|
||||
{closeText || <Icon type="close" />}
|
||||
{closeText || <Icon type="cross" />}
|
||||
</a>
|
||||
) : null;
|
||||
|
||||
const dataOrAriaProps = getDataOrAriaProps(this.props);
|
||||
|
||||
const iconNode = (icon &&
|
||||
(React.isValidElement<{ className?: string }>(icon) ? (
|
||||
React.cloneElement(icon, {
|
||||
className: classNames({
|
||||
[icon.props.className as string]: icon.props.className,
|
||||
[`${prefixCls}-icon`]: true,
|
||||
}),
|
||||
})
|
||||
) : (
|
||||
<span className={`${prefixCls}-icon`}>{icon}</span>
|
||||
))) || <Icon className={`${prefixCls}-icon`} type={iconType} theme={iconTheme} />;
|
||||
|
||||
return this.state.closed ? null : (
|
||||
<Animate
|
||||
component=""
|
||||
@@ -160,17 +116,13 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
||||
transitionName={`${prefixCls}-slide-up`}
|
||||
onEnd={this.animationEnd}
|
||||
>
|
||||
<div data-show={this.state.closing} className={alertCls} style={style} {...dataOrAriaProps}>
|
||||
{showIcon ? iconNode : null}
|
||||
<div data-show={this.state.closing} className={alertCls} style={style}>
|
||||
{showIcon ? <Icon className={`${prefixCls}-icon`} type={iconType} /> : null}
|
||||
<span className={`${prefixCls}-message`}>{message}</span>
|
||||
<span className={`${prefixCls}-description`}>{description}</span>
|
||||
{closeIcon}
|
||||
</div>
|
||||
</Animate>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAlert}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 警告提示
|
||||
type: 反馈
|
||||
type: Feedback
|
||||
title: Alert
|
||||
---
|
||||
|
||||
@@ -16,13 +16,11 @@ title: Alert
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| afterClose | 关闭动画结束后触发的回调函数 | () => void | - |
|
||||
| banner | 是否用作顶部公告 | boolean | false |
|
||||
| closable | 默认不显示关闭按钮 | boolean | 无 |
|
||||
| closeText | 自定义关闭按钮 | string\|ReactNode | 无 |
|
||||
| description | 警告提示的辅助性文字介绍 | string\|ReactNode | 无 |
|
||||
| icon | 自定义图标,`showIcon` 为 `true` 时有效 | ReactNode | - |
|
||||
| message | 警告提示内容 | string\|ReactNode | 无 |
|
||||
| showIcon | 是否显示辅助图标 | boolean | false,`banner` 模式下默认值为 true |
|
||||
| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | string | `info`,`banner` 模式下默认值为 `warning` |
|
||||
| onClose | 关闭时触发的回调函数 | (e: MouseEvent) => void | 无 |
|
||||
| onClose | 关闭时触发的回调函数 | Function | 无 |
|
||||
|
||||
@@ -1,85 +1,82 @@
|
||||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
@import "../../style/themes/default";
|
||||
|
||||
@alert-prefix-cls: ~'@{ant-prefix}-alert';
|
||||
@alert-prefix-cls: ~"@{ant-prefix}-alert";
|
||||
|
||||
@alert-message-color: @heading-color;
|
||||
@alert-text-color: @text-color;
|
||||
@alert-close-color: @text-color-secondary;
|
||||
@alert-close-hover-color: @icon-color-hover;
|
||||
|
||||
.@{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;
|
||||
}
|
||||
|
||||
&&-closable {
|
||||
padding-right: 30px;
|
||||
padding: 8px 48px 8px 16px;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2;
|
||||
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 @alert-success-border-color;
|
||||
background-color: @alert-success-bg-color;
|
||||
border: @border-width-base @border-style-base @green-2;
|
||||
background-color: @green-1;
|
||||
.@{alert-prefix-cls}-icon {
|
||||
color: @alert-success-icon-color;
|
||||
color: @success-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
border: @border-width-base @border-style-base @alert-info-border-color;
|
||||
background-color: @alert-info-bg-color;
|
||||
border: @border-width-base @border-style-base @primary-2;
|
||||
background-color: @primary-1;
|
||||
.@{alert-prefix-cls}-icon {
|
||||
color: @alert-info-icon-color;
|
||||
color: @info-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-warning {
|
||||
border: @border-width-base @border-style-base @alert-warning-border-color;
|
||||
background-color: @alert-warning-bg-color;
|
||||
border: @border-width-base @border-style-base @yellow-2;
|
||||
background-color: @yellow-1;
|
||||
.@{alert-prefix-cls}-icon {
|
||||
color: @alert-warning-icon-color;
|
||||
color: @warning-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-error {
|
||||
border: @border-width-base @border-style-base @alert-error-border-color;
|
||||
background-color: @alert-error-bg-color;
|
||||
border: @border-width-base @border-style-base @red-2;
|
||||
background-color: @red-1;
|
||||
.@{alert-prefix-cls}-icon {
|
||||
color: @alert-error-icon-color;
|
||||
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}-close {
|
||||
color: @alert-close-color;
|
||||
transition: color 0.3s;
|
||||
.@{iconfont-css-prefix}-cross {
|
||||
color: @text-color-secondary;
|
||||
transition: color .3s ease;
|
||||
&:hover {
|
||||
color: @alert-close-hover-color;
|
||||
color: #404040;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,21 +87,21 @@
|
||||
}
|
||||
|
||||
&-with-description {
|
||||
padding: 15px 15px 15px 64px;
|
||||
padding: 16px 16px 16px 60px;
|
||||
position: relative;
|
||||
border-radius: @border-radius-base;
|
||||
color: @alert-text-color;
|
||||
line-height: @line-height-base;
|
||||
color: @text-color;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -132,12 +129,12 @@
|
||||
margin: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
transition: all 0.3s @ease-in-out-circ;
|
||||
transition: all .3s @ease-in-out-circ;
|
||||
transform-origin: 50% 0;
|
||||
}
|
||||
|
||||
&-slide-up-leave {
|
||||
animation: antAlertSlideUpOut 0.3s @ease-in-out-circ;
|
||||
animation: antAlertSlideUpOut .3s @ease-in-out-circ;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import * as PropTypes from 'prop-types';
|
||||
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';
|
||||
import Affix from '../affix';
|
||||
import AnchorLink from './AnchorLink';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import raf from 'raf';
|
||||
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
|
||||
|
||||
function getDefaultContainer() {
|
||||
function getDefaultTarget() {
|
||||
return window;
|
||||
}
|
||||
|
||||
function getOffsetTop(element: HTMLElement, container: AnchorContainer): number {
|
||||
function getOffsetTop(element: HTMLElement): number {
|
||||
if (!element) {
|
||||
return 0;
|
||||
}
|
||||
@@ -25,11 +24,9 @@ function getOffsetTop(element: HTMLElement, container: AnchorContainer): number
|
||||
const rect = element.getBoundingClientRect();
|
||||
|
||||
if (rect.width || rect.height) {
|
||||
if (container === window) {
|
||||
container = element.ownerDocument!.documentElement!;
|
||||
return rect.top - container.clientTop;
|
||||
}
|
||||
return rect.top - (container as HTMLElement).getBoundingClientRect().top;
|
||||
const doc = element.ownerDocument;
|
||||
const docElem = doc.documentElement;
|
||||
return rect.top - docElem.clientTop;
|
||||
}
|
||||
|
||||
return rect.top;
|
||||
@@ -39,56 +36,43 @@ function easeInOutCubic(t: number, b: number, c: number, d: number) {
|
||||
const cc = c - b;
|
||||
t /= d / 2;
|
||||
if (t < 1) {
|
||||
return (cc / 2) * t * t * t + b;
|
||||
return cc / 2 * t * t * t + b;
|
||||
}
|
||||
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
|
||||
return cc / 2 * ((t -= 2) * t * t + 2) + b;
|
||||
}
|
||||
|
||||
const reqAnimFrame = getRequestAnimationFrame();
|
||||
const sharpMatcherRegx = /#([^#]+)$/;
|
||||
function scrollTo(
|
||||
href: string,
|
||||
offsetTop = 0,
|
||||
getContainer: () => AnchorContainer,
|
||||
callback = () => {},
|
||||
) {
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
function scrollTo(href: string, offsetTop = 0, target, callback = () => { }) {
|
||||
const scrollTop = getScroll(target(), true);
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(href);
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
if (!sharpLinkMatch) { return; }
|
||||
const targetElement = document.getElementById(sharpLinkMatch[1]);
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
const eleOffsetTop = getOffsetTop(targetElement);
|
||||
const targetScrollTop = scrollTop + eleOffsetTop - offsetTop;
|
||||
const startTime = Date.now();
|
||||
const frameFunc = () => {
|
||||
const timestamp = Date.now();
|
||||
const time = timestamp - startTime;
|
||||
const nextScrollTop = easeInOutCubic(time, scrollTop, targetScrollTop, 450);
|
||||
if (container === window) {
|
||||
window.scrollTo(window.pageXOffset, nextScrollTop);
|
||||
} else {
|
||||
(container as HTMLElement).scrollTop = nextScrollTop;
|
||||
}
|
||||
window.scrollTo(window.pageXOffset, easeInOutCubic(time, scrollTop, targetScrollTop, 450));
|
||||
if (time < 450) {
|
||||
raf(frameFunc);
|
||||
reqAnimFrame(frameFunc);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
raf(frameFunc);
|
||||
reqAnimFrame(frameFunc);
|
||||
history.pushState(null, '', href);
|
||||
}
|
||||
|
||||
type Section = {
|
||||
link: string;
|
||||
link: String;
|
||||
top: number;
|
||||
};
|
||||
|
||||
export type AnchorContainer = HTMLElement | Window;
|
||||
|
||||
export interface AnchorProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
@@ -98,83 +82,61 @@ export interface AnchorProps {
|
||||
bounds?: number;
|
||||
affix?: boolean;
|
||||
showInkInFixed?: boolean;
|
||||
getContainer?: () => AnchorContainer;
|
||||
onClick?: (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: { title: React.ReactNode; href: string },
|
||||
) => void;
|
||||
target?: () => HTMLElement | Window;
|
||||
}
|
||||
|
||||
export interface AnchorState {
|
||||
activeLink: null | string;
|
||||
}
|
||||
|
||||
export interface AnchorDefaultProps extends AnchorProps {
|
||||
prefixCls: string;
|
||||
affix: boolean;
|
||||
showInkInFixed: boolean;
|
||||
getContainer: () => AnchorContainer;
|
||||
}
|
||||
|
||||
export interface AntAnchor {
|
||||
registerLink: (link: string) => void;
|
||||
unregisterLink: (link: string) => void;
|
||||
activeLink: string | null;
|
||||
scrollTo: (link: string) => void;
|
||||
onClick?: (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: { title: React.ReactNode; href: string },
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
export default class Anchor extends React.Component<AnchorProps, any> {
|
||||
static Link: typeof AnchorLink;
|
||||
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-anchor',
|
||||
affix: true,
|
||||
showInkInFixed: false,
|
||||
getContainer: getDefaultContainer,
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
antAnchor: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {
|
||||
activeLink: null,
|
||||
refs: {
|
||||
ink?: any;
|
||||
};
|
||||
|
||||
private inkNode: HTMLSpanElement;
|
||||
|
||||
private links: string[] = [];
|
||||
private links: String[];
|
||||
private scrollEvent: any;
|
||||
private animating: boolean;
|
||||
|
||||
private prefixCls?: string;
|
||||
constructor(props: AnchorProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
activeLink: null,
|
||||
};
|
||||
this.links = [];
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
const antAnchor: AntAnchor = {
|
||||
registerLink: (link: string) => {
|
||||
if (!this.links.includes(link)) {
|
||||
this.links.push(link);
|
||||
}
|
||||
return {
|
||||
antAnchor: {
|
||||
registerLink: (link: String) => {
|
||||
if (!this.links.includes(link)) {
|
||||
this.links.push(link);
|
||||
}
|
||||
},
|
||||
unregisterLink: (link: String) => {
|
||||
const index = this.links.indexOf(link);
|
||||
if (index !== -1) {
|
||||
this.links.splice(index, 1);
|
||||
}
|
||||
},
|
||||
activeLink: this.state.activeLink,
|
||||
scrollTo: this.handleScrollTo,
|
||||
},
|
||||
unregisterLink: (link: string) => {
|
||||
const index = this.links.indexOf(link);
|
||||
if (index !== -1) {
|
||||
this.links.splice(index, 1);
|
||||
}
|
||||
},
|
||||
activeLink: this.state.activeLink,
|
||||
scrollTo: this.handleScrollTo,
|
||||
onClick: this.props.onClick,
|
||||
};
|
||||
return { antAnchor };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { getContainer } = this.props as AnchorDefaultProps;
|
||||
this.scrollEvent = addEventListener(getContainer(), 'scroll', this.handleScroll);
|
||||
const getTarget = this.props.target || getDefaultTarget;
|
||||
this.scrollEvent = addEventListener(getTarget(), 'scroll', this.handleScroll);
|
||||
this.handleScroll();
|
||||
}
|
||||
|
||||
@@ -196,45 +158,39 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
this.setState({
|
||||
activeLink: this.getCurrentAnchor(offsetTop, bounds),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
handleScrollTo = (link: string) => {
|
||||
const { offsetTop, getContainer } = this.props as AnchorDefaultProps;
|
||||
handleScrollTo = (link) => {
|
||||
const { offsetTop, target = getDefaultTarget } = this.props;
|
||||
this.animating = true;
|
||||
this.setState({ activeLink: link });
|
||||
scrollTo(link, offsetTop, getContainer, () => {
|
||||
scrollTo(link, offsetTop, target, () => {
|
||||
this.animating = false;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
getCurrentAnchor(offsetTop = 0, bounds = 5): string {
|
||||
const activeLink = '';
|
||||
getCurrentAnchor(offsetTop = 0, bounds = 5) {
|
||||
let activeLink = '';
|
||||
if (typeof document === 'undefined') {
|
||||
return activeLink;
|
||||
}
|
||||
|
||||
const linkSections: Array<Section> = [];
|
||||
const { getContainer } = this.props as AnchorDefaultProps;
|
||||
const container = getContainer();
|
||||
this.links.forEach(link => {
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link.toString());
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
if (!sharpLinkMatch) { return; }
|
||||
const target = document.getElementById(sharpLinkMatch[1]);
|
||||
if (target) {
|
||||
const top = getOffsetTop(target, container);
|
||||
if (top < offsetTop + bounds) {
|
||||
linkSections.push({
|
||||
link,
|
||||
top,
|
||||
});
|
||||
}
|
||||
if (target && getOffsetTop(target) < offsetTop + bounds) {
|
||||
const top = getOffsetTop(target);
|
||||
linkSections.push({
|
||||
link,
|
||||
top,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (linkSections.length) {
|
||||
const maxSection = linkSections.reduce((prev, curr) => (curr.top > prev.top ? curr : prev));
|
||||
const maxSection = linkSections.reduce((prev, curr) => curr.top > prev.top ? curr : prev);
|
||||
return maxSection.link;
|
||||
}
|
||||
return '';
|
||||
@@ -244,38 +200,25 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const prefixCls = this.prefixCls;
|
||||
const anchorNode = ReactDOM.findDOMNode(this) as Element;
|
||||
const linkNode = anchorNode.getElementsByClassName(`${prefixCls}-link-title-active`)[0];
|
||||
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;
|
||||
};
|
||||
|
||||
renderAnchor = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
render() {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
prefixCls,
|
||||
className = '',
|
||||
style,
|
||||
offsetTop,
|
||||
affix,
|
||||
showInkInFixed,
|
||||
children,
|
||||
getContainer,
|
||||
} = this.props;
|
||||
const { activeLink } = this.state;
|
||||
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
|
||||
// To support old version react.
|
||||
// Have to add prefixCls on the instance.
|
||||
// https://github.com/facebook/react/issues/12397
|
||||
this.prefixCls = prefixCls;
|
||||
|
||||
const inkClass = classNames(`${prefixCls}-ink-ball`, {
|
||||
visible: activeLink,
|
||||
});
|
||||
@@ -283,35 +226,24 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
const wrapperClass = classNames(className, `${prefixCls}-wrapper`);
|
||||
|
||||
const anchorClass = classNames(prefixCls, {
|
||||
fixed: !affix && !showInkInFixed,
|
||||
'fixed': !affix && !showInkInFixed,
|
||||
});
|
||||
|
||||
const wrapperStyle = {
|
||||
maxHeight: offsetTop ? `calc(100vh - ${offsetTop}px)` : '100vh',
|
||||
...style,
|
||||
};
|
||||
|
||||
const anchorContent = (
|
||||
<div className={wrapperClass} style={wrapperStyle}>
|
||||
<div className={wrapperClass} style={style}>
|
||||
<div className={anchorClass}>
|
||||
<div className={`${prefixCls}-ink`}>
|
||||
<span className={inkClass} ref={this.saveInkNode} />
|
||||
<div className={`${prefixCls}-ink`} >
|
||||
<span className={inkClass} ref="ink" />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return !affix ? (
|
||||
anchorContent
|
||||
) : (
|
||||
<Affix offsetTop={offsetTop} target={getContainer}>
|
||||
return !affix ? anchorContent : (
|
||||
<Affix offsetTop={offsetTop}>
|
||||
{anchorContent}
|
||||
</Affix>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAnchor}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { AntAnchor } from './Anchor';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
|
||||
export interface AnchorLinkProps {
|
||||
prefixCls?: string;
|
||||
href: string;
|
||||
title: React.ReactNode;
|
||||
children?: any;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-anchor',
|
||||
href: '#',
|
||||
};
|
||||
|
||||
@@ -23,39 +20,30 @@ class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
};
|
||||
|
||||
context: {
|
||||
antAnchor: AntAnchor;
|
||||
antAnchor: any;
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.context.antAnchor.registerLink(this.props.href);
|
||||
}
|
||||
|
||||
componentDidUpdate({ href: prevHref }: AnchorLinkProps) {
|
||||
const { href } = this.props;
|
||||
if (prevHref !== href) {
|
||||
this.context.antAnchor.unregisterLink(prevHref);
|
||||
this.context.antAnchor.registerLink(href);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.context.antAnchor.unregisterLink(this.props.href);
|
||||
}
|
||||
|
||||
handleClick = (e: React.MouseEvent<HTMLElement>) => {
|
||||
const { scrollTo, onClick } = this.context.antAnchor;
|
||||
const { href, title } = this.props;
|
||||
if (onClick) {
|
||||
onClick(e, { title, href });
|
||||
}
|
||||
scrollTo(href);
|
||||
};
|
||||
handleClick = () => {
|
||||
this.context.antAnchor.scrollTo(this.props.href);
|
||||
}
|
||||
|
||||
renderAnchorLink = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, href, title, children, className } = this.props;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
render() {
|
||||
const {
|
||||
prefixCls,
|
||||
href,
|
||||
title,
|
||||
children,
|
||||
} = this.props;
|
||||
const active = this.context.antAnchor.activeLink === href;
|
||||
const wrapperClassName = classNames(className, `${prefixCls}-link`, {
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
@@ -74,13 +62,5 @@ class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAnchorLink}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
polyfill(AnchorLink);
|
||||
|
||||
export default AnchorLink;
|
||||
|
||||
@@ -9,26 +9,26 @@ describe('Anchor Render', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
</Anchor>
|
||||
);
|
||||
|
||||
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>,
|
||||
</Anchor>
|
||||
);
|
||||
wrapper.find('a[href="http://www.example.com/#API"]').simulate('click');
|
||||
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
|
||||
expect(wrapper.node.state.activeLink).toBe('http://www.example.com/#API');
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scroll', () => {
|
||||
it('Anchor render perfectly for complete href - scoll', () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
@@ -39,14 +39,13 @@ describe('Anchor Render', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>,
|
||||
</Anchor>
|
||||
);
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
|
||||
wrapper.node.handleScroll();
|
||||
expect(wrapper.node.state.activeLink).toBe('http://www.example.com/#API');
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
it('Anchor render perfectly for complete href - scollTo', () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
@@ -57,77 +56,9 @@ describe('Anchor Render', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="##API" title="API" />
|
||||
</Anchor>,
|
||||
</Anchor>
|
||||
);
|
||||
wrapper.instance().handleScrollTo('##API');
|
||||
expect(wrapper.instance().state.activeLink).toBe('##API');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should remove listener when unmount', async () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
wrapper.unmount();
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unregister link when unmount children', async () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(wrapper.instance().links).toEqual(['#API']);
|
||||
wrapper.setProps({ children: null });
|
||||
expect(wrapper.instance().links).toEqual([]);
|
||||
});
|
||||
|
||||
it('should update links when link href update', async () => {
|
||||
let anchorInstance = null;
|
||||
function AnchorUpdate({ href }) {
|
||||
return (
|
||||
<Anchor
|
||||
ref={c => {
|
||||
anchorInstance = c;
|
||||
}}
|
||||
>
|
||||
<Link href={href} title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
}
|
||||
const wrapper = mount(<AnchorUpdate href="#API" />);
|
||||
|
||||
expect(anchorInstance.links).toEqual(['#API']);
|
||||
wrapper.setProps({ href: '#API_1' });
|
||||
expect(anchorInstance.links).toEqual(['#API_1']);
|
||||
});
|
||||
|
||||
it('Anchor onClick event', () => {
|
||||
let event;
|
||||
let link;
|
||||
const handleClick = (...arg) => {
|
||||
[event, link] = arg;
|
||||
};
|
||||
|
||||
const href = '#API';
|
||||
const title = 'API';
|
||||
|
||||
const wrapper = mount(
|
||||
<Anchor onClick={handleClick}>
|
||||
<Link href={href} title={title} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="${href}"]`).simulate('click');
|
||||
|
||||
wrapper.instance().handleScroll();
|
||||
expect(event).not.toBe(undefined);
|
||||
expect(link).toEqual({ href, title });
|
||||
wrapper.node.handleScrollTo('##API');
|
||||
expect(wrapper.node.state.activeLink).toBe('##API');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
@@ -35,10 +34,10 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
href="#components-anchor-demo-fixed"
|
||||
title="Fixed demo"
|
||||
>
|
||||
Static demo
|
||||
Fixed demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
@@ -80,10 +79,9 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onClick.md correctly 1`] = `
|
||||
exports[`renders ./components/anchor/demo/fixed.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor fixed"
|
||||
@@ -111,84 +109,10 @@ exports[`renders ./components/anchor/demo/onClick.md correctly 1`] = `
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
href="#components-anchor-demo-fixed"
|
||||
title="Fixed demo"
|
||||
>
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#API"
|
||||
title="API"
|
||||
>
|
||||
API
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#Anchor-Props"
|
||||
title="Anchor Props"
|
||||
>
|
||||
Anchor Props
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#Link-Props"
|
||||
title="Link Props"
|
||||
>
|
||||
Link Props
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/static.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor fixed"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-ink"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink-ball"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
title="Basic demo"
|
||||
>
|
||||
Basic demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
Static demo
|
||||
Fixed demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -15,20 +15,18 @@ The simplest usage.
|
||||
|
||||
```jsx
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
ReactDOM.render(
|
||||
<Anchor>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#components-anchor-demo-fixed" title="Fixed demo" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>,
|
||||
mountNode
|
||||
);
|
||||
</Anchor>
|
||||
, mountNode);
|
||||
```
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
zh-CN: 静态位置
|
||||
en-US: Static Anchor
|
||||
zh-CN: 固定
|
||||
en-US: Fixed Anchor
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
@@ -15,18 +15,16 @@ Do not change state when page is scrolling.
|
||||
|
||||
```jsx
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
ReactDOM.render(
|
||||
<Anchor affix={false}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#components-anchor-demo-fixed" title="Fixed demo" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>,
|
||||
mountNode
|
||||
);
|
||||
</Anchor>
|
||||
, mountNode);
|
||||
```
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 自定义 onClick 事件
|
||||
en-US: Customize the onClick event
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
点击锚点不记录历史。
|
||||
|
||||
## en-US
|
||||
|
||||
Clicking on an anchor does not record history.
|
||||
|
||||
```jsx
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const handleClick = (e, link) => {
|
||||
e.preventDefault();
|
||||
console.log(link);
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<Anchor affix={false} onClick={handleClick}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>,
|
||||
mountNode
|
||||
);
|
||||
```
|
||||
@@ -17,13 +17,11 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| affix | Fixed mode of Anchor | boolean | true |
|
||||
| affix | Fixed mode of Anchor | boolean | false |
|
||||
| bounds | Bounding distance of anchor area | number | 5(px) |
|
||||
| getContainer | Scrolling container | () => HTMLElement | () => window |
|
||||
| offsetBottom | Pixels to offset from bottom when calculating position of scroll | number | - |
|
||||
| offsetTop | Pixels to offset from top when calculating position of scroll | number | 0 |
|
||||
| showInkInFixed | Whether show ink-balls in Fixed mode | boolean | false |
|
||||
| onClick | set the handler to handle `click` event | Function(e: Event, link: Object) | - |
|
||||
|
||||
### Link Props
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
category: Components
|
||||
subtitle: 锚点
|
||||
cols: 2
|
||||
type: 其他
|
||||
type: Other
|
||||
title: Anchor
|
||||
---
|
||||
|
||||
@@ -18,13 +18,11 @@ title: Anchor
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| affix | 固定模式 | boolean | true |
|
||||
| affix | 固定模式 | boolean | false |
|
||||
| bounds | 锚点区域边界 | number | 5(px) |
|
||||
| getContainer | 指定滚动的容器 | () => HTMLElement | () => window |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | number | |
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | |
|
||||
| showInkInFixed | 固定模式是否显示小圆点 | boolean | false |
|
||||
| onClick | `click` 事件的 handler | Function(e: Event, link: Object) | - |
|
||||
|
||||
### Link Props
|
||||
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@anchor-border-width: 2px;
|
||||
@import "../../style/themes/default";
|
||||
|
||||
.@{ant-prefix}-anchor {
|
||||
.reset-component;
|
||||
position: relative;
|
||||
padding-left: @anchor-border-width;
|
||||
|
||||
&-wrapper {
|
||||
background-color: @component-background;
|
||||
overflow: auto;
|
||||
padding-left: 4px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
&-ink {
|
||||
@@ -23,7 +14,7 @@
|
||||
&:before {
|
||||
content: ' ';
|
||||
position: relative;
|
||||
width: @anchor-border-width;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
background-color: @border-color-split;
|
||||
@@ -32,13 +23,13 @@
|
||||
&-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 0.3s ease-in-out;
|
||||
transition: top .3s ease-in-out;
|
||||
transform: translateX(-50%);
|
||||
&.visible {
|
||||
display: inline-block;
|
||||
@@ -51,18 +42,18 @@
|
||||
}
|
||||
|
||||
&-link {
|
||||
padding: 7px 0 7px 16px;
|
||||
line-height: 1.143;
|
||||
padding: 8px 0 8px 18px;
|
||||
line-height: 1;
|
||||
|
||||
&-title {
|
||||
display: block;
|
||||
position: relative;
|
||||
transition: all 0.3s;
|
||||
transition: all .3s;
|
||||
color: @text-color;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:only-child {
|
||||
margin-bottom: 0;
|
||||
@@ -75,7 +66,7 @@
|
||||
}
|
||||
|
||||
&-link &-link {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
render() {
|
||||
return React.cloneElement(
|
||||
this.props.children,
|
||||
{
|
||||
...this.props,
|
||||
ref: this.saveRef,
|
||||
},
|
||||
null,
|
||||
);
|
||||
return React.cloneElement(this.props.children, {
|
||||
...this.props,
|
||||
ref: this.saveRef,
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
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"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
@@ -19,8 +18,8 @@ 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"
|
||||
unselectable="on"
|
||||
style="display:block;user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
@@ -47,27 +46,10 @@ exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
style="user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<b />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,15 +58,14 @@ 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"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
@@ -96,8 +77,8 @@ 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"
|
||||
unselectable="on"
|
||||
style="display:block;user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
@@ -120,23 +101,8 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: search"
|
||||
class="anticon anticon-search certain-category-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
@@ -150,27 +116,10 @@ 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"
|
||||
unselectable="on"
|
||||
style="user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<b />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,11 +129,10 @@ 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"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
@@ -204,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"
|
||||
@@ -217,27 +165,10 @@ exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
style="user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<b />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,11 +177,10 @@ 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"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
@@ -262,8 +192,8 @@ 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"
|
||||
unselectable="on"
|
||||
style="display:block;user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
try to type \`b\`
|
||||
</div>
|
||||
@@ -290,27 +220,10 @@ 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"
|
||||
unselectable="on"
|
||||
style="user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<b />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -319,11 +232,10 @@ 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"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
@@ -335,8 +247,8 @@ 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"
|
||||
unselectable="on"
|
||||
style="display:block;user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
@@ -363,27 +275,10 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
style="user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<b />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -392,15 +287,14 @@ 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"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
@@ -412,8 +306,8 @@ 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"
|
||||
unselectable="on"
|
||||
style="display:block;user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
@@ -440,23 +334,8 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: search"
|
||||
class="anticon anticon-search"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
@@ -471,27 +350,10 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
style="user-select:none;-webkit-user-select:none;"
|
||||
unselectable="unselectable"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<b />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
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']}>
|
||||
<textarea />
|
||||
</AutoComplete>,
|
||||
</AutoComplete>
|
||||
);
|
||||
|
||||
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);
|
||||
@@ -31,7 +23,7 @@ describe('AutoComplete with Custom Input Element Render', () => {
|
||||
mount(
|
||||
<AutoComplete dataSource={[]}>
|
||||
<input ref={mockRef} />
|
||||
</AutoComplete>,
|
||||
</AutoComplete>
|
||||
);
|
||||
expect(mockRef).toHaveBeenCalled();
|
||||
});
|
||||
@@ -16,7 +16,6 @@ Basic Usage, set datasource of autocomplete with `dataSource` property.
|
||||
|
||||
````jsx
|
||||
import { Icon, Input, AutoComplete } from 'antd';
|
||||
|
||||
const Option = AutoComplete.Option;
|
||||
const OptGroup = AutoComplete.OptGroup;
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ Customize Input Component
|
||||
|
||||
````jsx
|
||||
import { AutoComplete, Input } from 'antd';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
function onSelect(value) {
|
||||
|
||||
@@ -35,7 +35,9 @@ class Complete extends React.Component {
|
||||
|
||||
render() {
|
||||
const { result } = this.state;
|
||||
const children = result.map(email => <Option key={email}>{email}</Option>);
|
||||
const children = result.map((email) => {
|
||||
return <Option key={email}>{email}</Option>;
|
||||
});
|
||||
return (
|
||||
<AutoComplete
|
||||
style={{ width: 200 }}
|
||||
|
||||
@@ -15,10 +15,7 @@ Demonstration of [Lookup Patterns: Uncertain Category](https://ant.design/docs/s
|
||||
Basic Usage, set datasource of autocomplete with `dataSource` property.
|
||||
|
||||
````jsx
|
||||
import {
|
||||
Icon, Button, Input, AutoComplete,
|
||||
} from 'antd';
|
||||
|
||||
import { Icon, Button, Input, AutoComplete } from 'antd';
|
||||
const Option = AutoComplete.Option;
|
||||
|
||||
function onSelect(value) {
|
||||
|
||||
@@ -21,30 +21,17 @@ 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<React.ReactElement<OptionProps>> | - |
|
||||
| dataSource | Data source for autocomplete | [DataSourceItemType](https://git.io/vMMKF)\[] | |
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true |
|
||||
| defaultValue | Initial selected option. | string\|string\[]\| - |
|
||||
| defaultValue | Initial selected option. | string\|string\[]\|{ key: string, label: string\|ReactNode }\|Array<{ key: string, label: string\|ReactNode }> | - |
|
||||
| disabled | Whether disabled select | boolean | false |
|
||||
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true |
|
||||
| optionLabelProp | Which prop value of option will render as content of select. | string | `children` |
|
||||
| placeholder | placeholder of input | string | - |
|
||||
| value | selected option | string\|string\[]\|{ key: string, label: string\|ReactNode }\|Array<{ key: string, label: string\|ReactNode }> | - |
|
||||
| onBlur | Called when leaving the component. | function() | - |
|
||||
| onChange | Called when select an option or input value change, or value of input is changed | function(value) | - |
|
||||
| onFocus | Called when entering the component | function() | - |
|
||||
| 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) | - |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - |
|
||||
| open | Controlled open state of dropdown | boolean | - |
|
||||
| onDropdownVisibleChange | Call when dropdown open | function(open) | - |
|
||||
|
||||
## Methods
|
||||
|
||||
| Name | Description |
|
||||
| ---- | ----------- |
|
||||
| blur() | remove focus |
|
||||
| focus() | get focus |
|
||||
|
||||
@@ -1,58 +1,45 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import { Option, OptGroup } from 'rc-select';
|
||||
import classNames from 'classnames';
|
||||
import InputElement from './InputElement';
|
||||
import Input, { InputProps } from '../input';
|
||||
import Select, { AbstractSelectProps, SelectValue, OptionProps, OptGroupProps } from '../select';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import Input from '../input';
|
||||
import InputElement from './InputElement';
|
||||
|
||||
export interface DataSourceItemObject {
|
||||
value: string;
|
||||
text: string;
|
||||
}
|
||||
export type DataSourceItemType =
|
||||
| string
|
||||
| DataSourceItemObject
|
||||
| React.ReactElement<OptionProps>
|
||||
| React.ReactElement<OptGroupProps>;
|
||||
export interface DataSourceItemObject { value: string; text: string; }
|
||||
export type DataSourceItemType = string | DataSourceItemObject;
|
||||
|
||||
export interface AutoCompleteInputProps {
|
||||
export interface InputProps {
|
||||
onChange?: React.FormEventHandler<any>;
|
||||
value: any;
|
||||
}
|
||||
|
||||
export type ValidInputElement =
|
||||
| HTMLInputElement
|
||||
| HTMLTextAreaElement
|
||||
| React.ReactElement<AutoCompleteInputProps>;
|
||||
HTMLInputElement |
|
||||
HTMLTextAreaElement |
|
||||
React.ReactElement<InputProps>;
|
||||
|
||||
export interface AutoCompleteProps extends AbstractSelectProps {
|
||||
value?: SelectValue;
|
||||
defaultValue?: SelectValue;
|
||||
dataSource?: DataSourceItemType[];
|
||||
autoFocus?: boolean;
|
||||
backfill?: boolean;
|
||||
dataSource: DataSourceItemType[];
|
||||
optionLabelProp?: string;
|
||||
onChange?: (value: SelectValue) => void;
|
||||
onSelect?: (value: SelectValue, option: Object) => any;
|
||||
onBlur?: (value: SelectValue) => void;
|
||||
onFocus?: () => void;
|
||||
children?:
|
||||
| ValidInputElement
|
||||
| React.ReactElement<InputProps>
|
||||
| React.ReactElement<OptionProps>
|
||||
| Array<React.ReactElement<OptionProps>>;
|
||||
children?: ValidInputElement |
|
||||
React.ReactElement<OptionProps> |
|
||||
Array<React.ReactElement<OptionProps>>;
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-select',
|
||||
transitionName: 'slide-up',
|
||||
optionLabelProp: 'children',
|
||||
choiceTransitionName: 'zoom',
|
||||
@@ -60,45 +47,22 @@ 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 ? (
|
||||
React.Children.only(this.props.children)
|
||||
) : (
|
||||
<Input />
|
||||
);
|
||||
const elementProps = { ...(element as React.ReactElement<any>).props };
|
||||
const element = children && React.isValidElement(children) && children.type !== Option ?
|
||||
React.Children.only(this.props.children) : <Input />;
|
||||
const elementProps = { ...element.props };
|
||||
// https://github.com/ant-design/ant-design/pull/7742
|
||||
delete elementProps.children;
|
||||
return <InputElement {...elementProps}>{element}</InputElement>;
|
||||
};
|
||||
|
||||
focus() {
|
||||
this.select.focus();
|
||||
return (
|
||||
<InputElement {...elementProps}>{element}</InputElement>
|
||||
);
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.select.blur();
|
||||
}
|
||||
|
||||
saveSelect = (node: any) => {
|
||||
this.select = node;
|
||||
};
|
||||
|
||||
renderAutoComplete = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
size,
|
||||
className = '',
|
||||
notFoundContent,
|
||||
optionLabelProp,
|
||||
dataSource,
|
||||
children,
|
||||
render() {
|
||||
let {
|
||||
size, className = '', notFoundContent, prefixCls, optionLabelProp, dataSource, children,
|
||||
} = this.props;
|
||||
const prefixCls = getPrefixCls('select', customizePrefixCls);
|
||||
|
||||
const cls = classNames({
|
||||
[`${prefixCls}-lg`]: size === 'large',
|
||||
@@ -110,48 +74,41 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
|
||||
|
||||
let options;
|
||||
const childArray = React.Children.toArray(children);
|
||||
if (childArray.length && isSelectOptionOrSelectOptGroup(childArray[0])) {
|
||||
if (childArray.length &&
|
||||
isSelectOptionOrSelectOptGroup(childArray[0])
|
||||
) {
|
||||
options = children;
|
||||
} else {
|
||||
options = dataSource
|
||||
? dataSource.map(item => {
|
||||
if (React.isValidElement(item)) {
|
||||
return item;
|
||||
}
|
||||
switch (typeof item) {
|
||||
case 'string':
|
||||
return <Option key={item}>{item}</Option>;
|
||||
case 'object':
|
||||
return (
|
||||
<Option key={(item as DataSourceItemObject).value}>
|
||||
{(item as DataSourceItemObject).text}
|
||||
</Option>
|
||||
);
|
||||
default:
|
||||
throw new Error(
|
||||
'AutoComplete[dataSource] only supports type `string[] | Object[]`.',
|
||||
);
|
||||
}
|
||||
})
|
||||
: [];
|
||||
options = dataSource ? dataSource.map((item) => {
|
||||
if (React.isValidElement(item)) {
|
||||
return item;
|
||||
}
|
||||
switch (typeof item) {
|
||||
case 'string':
|
||||
return <Option key={item}>{item}</Option>;
|
||||
case 'object':
|
||||
return (
|
||||
<Option key={(item as DataSourceItemObject).value}>
|
||||
{(item as DataSourceItemObject).text}
|
||||
</Option>
|
||||
);
|
||||
default:
|
||||
throw new Error('AutoComplete[dataSource] only supports type `string[] | Object[]`.');
|
||||
}
|
||||
}) : [];
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
{...this.props}
|
||||
className={cls}
|
||||
mode={Select.SECRET_COMBOBOX_MODE_DO_NOT_USE}
|
||||
mode="combobox"
|
||||
optionLabelProp={optionLabelProp}
|
||||
getInputElement={this.getInputElement}
|
||||
notFoundContent={notFoundContent}
|
||||
ref={this.saveSelect}
|
||||
>
|
||||
{options}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAutoComplete}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 自动完成
|
||||
type: 数据录入
|
||||
type: Data Entry
|
||||
cols: 2
|
||||
title: AutoComplete
|
||||
---
|
||||
@@ -22,30 +22,17 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| allowClear | 支持清除, 单选模式有效 | boolean | false |
|
||||
| autoFocus | 自动获取焦点 | boolean | false |
|
||||
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false |
|
||||
| children (自动完成的数据源) | 自动完成的数据源 | React.ReactElement<OptionProps> / Array<React.ReactElement<OptionProps>> | - |
|
||||
| children (自定义输入框) | 自定义输入框 | HTMLInputElement / HTMLTextAreaElement / React.ReactElement<InputProps> | `<Input />` |
|
||||
| dataSource | 自动完成的数据源 | [DataSourceItemType](https://git.io/vMMKF)\[] | |
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true |
|
||||
| defaultValue | 指定默认选中的条目 | string\|string\[]\| 无 |
|
||||
| defaultValue | 指定默认选中的条目 | string\|string\[]\|{ key: string, label: string\|ReactNode }\|Array<{ key: string, label: string\|ReactNode}> | 无 |
|
||||
| disabled | 是否禁用 | boolean | false |
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true |
|
||||
| optionLabelProp | 回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 `value`。 | string | `children` |
|
||||
| placeholder | 输入框提示 | string | - |
|
||||
| value | 指定当前选中的条目 | string\|string\[]\|{ key: string, label: string\|ReactNode }\|Array<{ key: string, label: string\|ReactNode }> | 无 |
|
||||
| onBlur | 失去焦点时的回调 | function() | - |
|
||||
| onChange | 选中 option,或 input 的 value 变化时,调用此函数 | function(value) | 无 |
|
||||
| onFocus | 获得焦点时的回调 | function() | - |
|
||||
| onSearch | 搜索补全项的时候调用 | function(value) | 无 |
|
||||
| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | 无 |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - |
|
||||
| open | 是否展开下拉菜单 | boolean | - |
|
||||
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - |
|
||||
|
||||
## 方法
|
||||
|
||||
| 名称 | 描述 |
|
||||
| --- | --- |
|
||||
| blur() | 移除焦点 |
|
||||
| focus() | 获取焦点 |
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
@import '../../input/style/mixin';
|
||||
@import "../../style/themes/default";
|
||||
@import "../../style/mixins/index";
|
||||
@import "../../input/style/mixin";
|
||||
|
||||
@input-prefix-cls: ~'@{ant-prefix}-input';
|
||||
@select-prefix-cls: ~'@{ant-prefix}-select';
|
||||
@autocomplete-prefix-cls: ~'@{select-prefix-cls}-auto-complete';
|
||||
@input-prefix-cls: ~"@{ant-prefix}-input";
|
||||
@select-prefix-cls: ~"@{ant-prefix}-select";
|
||||
@autocomplete-prefix-cls: ~"@{select-prefix-cls}-auto-complete";
|
||||
|
||||
.@{autocomplete-prefix-cls} {
|
||||
.reset-component;
|
||||
|
||||
&.@{select-prefix-cls} {
|
||||
.@{select-prefix-cls} {
|
||||
&-selection {
|
||||
@@ -52,10 +50,6 @@
|
||||
&:hover {
|
||||
.hover;
|
||||
}
|
||||
&[disabled] {
|
||||
.disabled;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&-lg {
|
||||
|
||||
@@ -8,86 +8,4 @@ describe('Avatar Render', () => {
|
||||
const children = wrapper.find('.ant-avatar-string');
|
||||
expect(children.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render fallback string correctly', () => {
|
||||
const div = global.document.createElement('div');
|
||||
global.document.body.appendChild(div);
|
||||
|
||||
const wrapper = mount(<Avatar src="http://error.url">Fallback</Avatar>, { attachTo: div });
|
||||
wrapper.instance().setScale = jest.fn(() => wrapper.instance().setState({ scale: 0.5 }));
|
||||
|
||||
wrapper.find('img').simulate('error');
|
||||
|
||||
const children = wrapper.find('.ant-avatar-string');
|
||||
expect(children.length).toBe(1);
|
||||
expect(children.text()).toBe('Fallback');
|
||||
expect(wrapper.instance().setScale).toBeCalled();
|
||||
expect(div.querySelector('.ant-avatar-string').style.transform).toContain('scale(0.5)');
|
||||
|
||||
wrapper.detach();
|
||||
global.document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it('should handle onError correctly', () => {
|
||||
const LOAD_FAILURE_SRC = 'http://error.url';
|
||||
const LOAD_SUCCESS_SRC = 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png';
|
||||
|
||||
const div = global.document.createElement('div');
|
||||
global.document.body.appendChild(div);
|
||||
|
||||
class Foo extends React.Component {
|
||||
state = {
|
||||
src: LOAD_FAILURE_SRC,
|
||||
};
|
||||
|
||||
handleImgError = () => {
|
||||
this.setState({
|
||||
src: LOAD_SUCCESS_SRC,
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { src } = this.state;
|
||||
return <Avatar src={src} onError={this.handleImgError} />;
|
||||
}
|
||||
}
|
||||
|
||||
const wrapper = mount(<Foo />, { attachTo: div });
|
||||
// mock img load Error, since jsdom do not load resource by default
|
||||
// https://github.com/jsdom/jsdom/issues/1816
|
||||
wrapper.find('img').simulate('error');
|
||||
|
||||
expect(wrapper.find(Avatar).instance().state.isImgExist).toBe(true);
|
||||
expect(div.querySelector('img').getAttribute('src')).toBe(LOAD_SUCCESS_SRC);
|
||||
|
||||
wrapper.detach();
|
||||
global.document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it('should show image on success after a failure state', () => {
|
||||
const LOAD_FAILURE_SRC = 'http://error.url';
|
||||
const LOAD_SUCCESS_SRC = 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png';
|
||||
|
||||
const div = global.document.createElement('div');
|
||||
global.document.body.appendChild(div);
|
||||
|
||||
// simulate error src url
|
||||
const wrapper = mount(<Avatar src={LOAD_FAILURE_SRC}>Fallback</Avatar>, { attachTo: div });
|
||||
wrapper.find('img').simulate('error');
|
||||
|
||||
expect(wrapper.find(Avatar).instance().state.isImgExist).toBe(false);
|
||||
expect(wrapper.find('.ant-avatar-string').length).toBe(1);
|
||||
|
||||
// simulate successful src url
|
||||
wrapper.setProps({ src: LOAD_SUCCESS_SRC });
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find(Avatar).instance().state.isImgExist).toBe(true);
|
||||
expect(wrapper.find('.ant-avatar-image').length).toBe(1);
|
||||
|
||||
// cleanup
|
||||
wrapper.detach();
|
||||
global.document.body.removeChild(div);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
@@ -12,23 +12,8 @@ exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-square ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<sup
|
||||
class="ant-scroll-number ant-badge-count"
|
||||
@@ -37,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=""
|
||||
@@ -201,23 +186,8 @@ exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-square ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<sup
|
||||
class="ant-scroll-number ant-badge-dot"
|
||||
@@ -231,185 +201,49 @@ exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
|
||||
exports[`renders ./components/avatar/demo/basic.md correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
style="width:64px;height:64px;line-height:64px;font-size:32px"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-sm ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-square ant-avatar-icon"
|
||||
style="width:64px;height:64px;line-height:64px;font-size:32px"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-square ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-square ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-sm ant-avatar-square ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -419,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"
|
||||
@@ -429,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>
|
||||
@@ -445,23 +279,8 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
@@ -490,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"
|
||||
@@ -500,26 +319,11 @@ 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
|
||||
aria-label="icon: user"
|
||||
class="anticon anticon-user"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="user"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -24,7 +24,6 @@ ReactDOM.render(
|
||||
<span>
|
||||
<Badge dot><Avatar shape="square" icon="user" /></Badge>
|
||||
</span>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -19,20 +19,17 @@ import { Avatar } from 'antd';
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<div>
|
||||
<Avatar size={64} icon="user" />
|
||||
<Avatar size="large" icon="user" />
|
||||
<Avatar icon="user" />
|
||||
<Avatar size="small" icon="user" />
|
||||
</div>
|
||||
<div>
|
||||
<Avatar shape="square" size={64} icon="user" />
|
||||
<Avatar shape="square" size="large" icon="user" />
|
||||
<Avatar shape="square" icon="user" />
|
||||
<Avatar shape="square" size="small" icon="user" />
|
||||
</div>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
<style>
|
||||
|
||||
@@ -27,7 +27,6 @@ class Autoset extends React.Component {
|
||||
color: colorList[0],
|
||||
};
|
||||
}
|
||||
|
||||
changeUser = () => {
|
||||
const index = UserList.indexOf(this.state.user);
|
||||
this.setState({
|
||||
@@ -35,21 +34,16 @@ class Autoset extends React.Component {
|
||||
color: index < colorList.length - 1 ? colorList[index + 1] : colorList[0],
|
||||
});
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Autoset />,
|
||||
mountNode);
|
||||
ReactDOM.render(<Autoset />
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -24,9 +24,8 @@ ReactDOM.render(
|
||||
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||
<Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>U</Avatar>
|
||||
<Avatar style={{ backgroundColor: '#87d068' }} icon="user" />
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
<style>
|
||||
|
||||
@@ -12,8 +12,5 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| icon | the `Icon` type for an icon avatar, see `Icon` Component | string | - |
|
||||
| shape | the shape of avatar | `circle` \| `square` | `circle` |
|
||||
| size | the size of the avatar | number \| string: `large` `small` `default` | `default` |
|
||||
| size | the size of the avatar | `large` \| `small` \| `default` | `default` |
|
||||
| src | the address of the image for an image avatar | string | - |
|
||||
| srcSet | a list of sources to use for different screen resolutions | string | - |
|
||||
| alt | This attribute defines the alternative text describing the image | string | - |
|
||||
| onError | handler when img load error,return false to prevent default fallback behavior | () => boolean | - |
|
||||
|
||||
@@ -1,31 +1,21 @@
|
||||
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';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
|
||||
export interface AvatarProps {
|
||||
/** Shape of avatar, options:`circle`, `square` */
|
||||
shape?: 'circle' | 'square';
|
||||
/*
|
||||
* Size of avatar, options: `large`, `small`, `default`
|
||||
* or a custom number size
|
||||
* */
|
||||
size?: 'large' | 'small' | 'default' | number;
|
||||
/** Size of avatar, options:`large`, `small`, `default` */
|
||||
size?: 'large' | 'small' | 'default';
|
||||
/** Src of image avatar */
|
||||
src?: string;
|
||||
/** Srcset of image avatar */
|
||||
srcSet?: string;
|
||||
/** Type of the Icon to be used in avatar */
|
||||
icon?: string;
|
||||
style?: React.CSSProperties;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
children?: any;
|
||||
alt?: string;
|
||||
/* callback when img load error */
|
||||
/* return false to prevent Avatar show default fallback behavior, then you can do fallback by your self*/
|
||||
onError?: () => boolean;
|
||||
}
|
||||
|
||||
export interface AvatarState {
|
||||
@@ -35,41 +25,37 @@ export interface AvatarState {
|
||||
|
||||
export default class Avatar extends React.Component<AvatarProps, AvatarState> {
|
||||
static defaultProps = {
|
||||
shape: 'circle' as AvatarProps['shape'],
|
||||
size: 'default' as AvatarProps['size'],
|
||||
};
|
||||
|
||||
state = {
|
||||
scale: 1,
|
||||
isImgExist: true,
|
||||
prefixCls: 'ant-avatar',
|
||||
shape: 'circle',
|
||||
size: 'default',
|
||||
};
|
||||
|
||||
private avatarChildren: any;
|
||||
|
||||
constructor(props: AvatarProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
scale: 1,
|
||||
isImgExist: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setScale();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: AvatarProps, prevState: AvatarState) {
|
||||
if (
|
||||
prevProps.children !== this.props.children ||
|
||||
(prevState.scale !== this.state.scale && this.state.scale === 1) ||
|
||||
prevState.isImgExist !== this.state.isImgExist
|
||||
) {
|
||||
if (prevProps.children !== this.props.children
|
||||
|| (prevState.scale !== this.state.scale && this.state.scale === 1)) {
|
||||
this.setScale();
|
||||
}
|
||||
|
||||
if (prevProps.src !== this.props.src) {
|
||||
this.setState({ isImgExist: true, scale: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
setScale = () => {
|
||||
const childrenNode = this.avatarChildren;
|
||||
if (childrenNode) {
|
||||
const childrenWidth = childrenNode.offsetWidth;
|
||||
const avatarNode = ReactDOM.findDOMNode(this) as Element;
|
||||
const avatarWidth = avatarNode.getBoundingClientRect().width;
|
||||
const avatarWidth = ReactDOM.findDOMNode(this).getBoundingClientRect().width;
|
||||
// add 4px gap for each side to get better performance
|
||||
if (avatarWidth - 8 < childrenWidth) {
|
||||
this.setState({
|
||||
@@ -81,33 +67,15 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
handleImgLoadError = () => {
|
||||
const { onError } = this.props;
|
||||
const errorFlag = onError ? onError() : undefined;
|
||||
if (errorFlag !== false) {
|
||||
this.setState({ isImgExist: false });
|
||||
}
|
||||
};
|
||||
handleImgLoadError = () => this.setState({ isImgExist: false });
|
||||
|
||||
renderAvatar = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
render() {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
shape,
|
||||
size,
|
||||
src,
|
||||
srcSet,
|
||||
icon,
|
||||
className,
|
||||
alt,
|
||||
...others
|
||||
prefixCls, shape, size, src, icon, className, ...others,
|
||||
} = this.props;
|
||||
|
||||
const { isImgExist, scale } = this.state;
|
||||
|
||||
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
|
||||
|
||||
const sizeCls = classNames({
|
||||
[`${prefixCls}-lg`]: size === 'large',
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
@@ -115,65 +83,55 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
|
||||
|
||||
const classString = classNames(prefixCls, className, sizeCls, {
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-image`]: src && isImgExist,
|
||||
[`${prefixCls}-image`]: src,
|
||||
[`${prefixCls}-icon`]: icon,
|
||||
});
|
||||
|
||||
const sizeStyle: React.CSSProperties =
|
||||
typeof size === 'number'
|
||||
? {
|
||||
width: size,
|
||||
height: size,
|
||||
lineHeight: `${size}px`,
|
||||
fontSize: icon ? size / 2 : 18,
|
||||
}
|
||||
: {};
|
||||
|
||||
let children = this.props.children;
|
||||
if (src && isImgExist) {
|
||||
children = <img src={src} srcSet={srcSet} onError={this.handleImgLoadError} alt={alt} />;
|
||||
if (src && this.state.isImgExist) {
|
||||
children = (
|
||||
<img
|
||||
src={src}
|
||||
onError={this.handleImgLoadError}
|
||||
/>
|
||||
);
|
||||
} else if (icon) {
|
||||
children = <Icon type={icon} />;
|
||||
} else {
|
||||
const childrenNode = this.avatarChildren;
|
||||
if (childrenNode || scale !== 1) {
|
||||
const transformString = `scale(${scale}) translateX(-50%)`;
|
||||
if (childrenNode || this.state.scale !== 1) {
|
||||
const childrenStyle: React.CSSProperties = {
|
||||
msTransform: transformString,
|
||||
WebkitTransform: transformString,
|
||||
transform: transformString,
|
||||
msTransform: `scale(${this.state.scale})`,
|
||||
WebkitTransform: `scale(${this.state.scale})`,
|
||||
transform: `scale(${this.state.scale})`,
|
||||
position: 'absolute',
|
||||
display: 'inline-block',
|
||||
left: `calc(50% - ${Math.round(childrenNode.offsetWidth / 2)}px)`,
|
||||
};
|
||||
const sizeChildrenStyle: React.CSSProperties =
|
||||
typeof size === 'number'
|
||||
? {
|
||||
lineHeight: `${size}px`,
|
||||
}
|
||||
: {};
|
||||
children = (
|
||||
<span
|
||||
className={`${prefixCls}-string`}
|
||||
ref={span => (this.avatarChildren = span)}
|
||||
style={{ ...sizeChildrenStyle, ...childrenStyle }}
|
||||
ref={span => this.avatarChildren = span}
|
||||
style={childrenStyle}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
children = (
|
||||
<span className={`${prefixCls}-string`} ref={span => (this.avatarChildren = span)}>
|
||||
<span
|
||||
className={`${prefixCls}-string`}
|
||||
ref={span => this.avatarChildren = span}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<span {...others} style={{ ...sizeStyle, ...others.style }} className={classString}>
|
||||
<span {...others} className={classString}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAvatar}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 头像
|
||||
type: 数据展示
|
||||
type: Data Display
|
||||
title: Avatar
|
||||
---
|
||||
|
||||
用来代表用户或事物,支持图片、图标或字符展示。
|
||||
|
||||
## 设计师专属
|
||||
|
||||
安装 [Kitchen Sketch 插件 💎](https://kitchen.alipay.com),一键填充高逼格头像和文本.
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| icon | 设置头像的图标类型,参考 `Icon` 组件 | string | - |
|
||||
| shape | 指定头像的形状 | Enum{ 'circle', 'square' } | `circle` |
|
||||
| size | 设置头像的大小 | number \| Enum{ 'large', 'small', 'default' } | `default` |
|
||||
| size | 设置头像的大小 | Enum{ 'large', 'small', 'default' } | `default` |
|
||||
| src | 图片类头像的资源地址 | string | - |
|
||||
| srcSet | 设置图片类头像响应式资源地址 | string | - |
|
||||
| alt | 图像无法显示时的替代文本 | string | - |
|
||||
| onError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为 | () => boolean | - |
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
@import "../../style/themes/default";
|
||||
|
||||
@avatar-prefix-cls: ~'@{ant-prefix}-avatar';
|
||||
@avatar-prefix-cls: ~"@{ant-prefix}-avatar";
|
||||
|
||||
.@{avatar-prefix-cls} {
|
||||
.reset-component;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
background: @avatar-bg;
|
||||
@@ -12,11 +10,6 @@
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
|
||||
&-image {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.avatar-size(@avatar-size-base, @avatar-font-size-base);
|
||||
|
||||
@@ -43,12 +36,10 @@
|
||||
width: @size;
|
||||
height: @size;
|
||||
line-height: @size;
|
||||
border-radius: 50%;
|
||||
border-radius: @size / 2;
|
||||
|
||||
&-string {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform-origin: 0 center;
|
||||
& > * {
|
||||
line-height: @size;
|
||||
}
|
||||
|
||||
&.@{avatar-prefix-cls}-icon {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user