mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-15 22:09:21 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd8016f236 | ||
|
|
137de1aebf | ||
|
|
463b9800a4 |
@@ -1,236 +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
|
||||
|
||||
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,2 +0,0 @@
|
||||
codecov:
|
||||
branch: master
|
||||
@@ -1,4 +1,4 @@
|
||||
# 🎨 editorconfig.org
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
components/**/*.js
|
||||
components/**/*.jsx
|
||||
components/*/__tests__/type.tsx
|
||||
!components/*/__tests__/**/*.js
|
||||
!components/*/demo/*
|
||||
!.*.js
|
||||
# Docs templates
|
||||
site/theme/template/IconDisplay/*.js
|
||||
site/theme/template/IconDisplay/*.jsx
|
||||
64
.eslintrc.js
64
.eslintrc.js
@@ -1,40 +1,44 @@
|
||||
const eslintrc = {
|
||||
extends: ['airbnb', 'prettier'],
|
||||
extends: ['eslint-config-airbnb'],
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
jasmine: true,
|
||||
mocha: true,
|
||||
jest: true,
|
||||
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/no-unresolved': 0,
|
||||
'import/no-extraneous-dependencies': 0,
|
||||
'no-param-reassign': 0,
|
||||
'no-return-assign': 0,
|
||||
'max-len': 0,
|
||||
'consistent-return': 0,
|
||||
'no-redeclare': 0,
|
||||
'react/require-extension': 0,
|
||||
'react/jsx-indent': 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,
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'react/no-danger': 0,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -46,22 +50,14 @@ if (process.env.RUN_ENV === 'DEMO') {
|
||||
};
|
||||
|
||||
Object.assign(eslintrc.rules, {
|
||||
indent: 0,
|
||||
'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,
|
||||
'react/prefer-es6-class': 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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
55
.github/CONTRIBUTING.md
vendored
55
.github/CONTRIBUTING.md
vendored
@@ -1,13 +1,56 @@
|
||||
# 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 documentaion](http://facebook.github.io/react/docs/getting-started.html) or just Google(not Baidu, seriously) your questions with keywork *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
|
||||
|
||||
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 disscuss 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 documentaion, 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.
|
||||
|
||||
40
.github/ISSUE_TEMPLATE.md
vendored
40
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,15 +1,35 @@
|
||||
<!--
|
||||
⚠️ ⚠️ ⚠️ IMPORTANT: Please use the following link to create a new issue: ⚠️ ⚠️ ⚠️
|
||||
|
||||
http://new-issue.ant.design
|
||||
|
||||
If your issue was not created using the app above, it will be closed immediately.
|
||||
-->
|
||||
<!-- Issue Template -->
|
||||
|
||||
<!--
|
||||
⚠️ ⚠️ ⚠️ 注意:请使用下面的链接来新建 issue: ⚠️ ⚠️ ⚠️
|
||||
antd 的用法咨询,建议通过以下渠道,官方 issues 目前没有足够精力提供此类咨询服务:
|
||||
|
||||
http://new-issue.ant.design
|
||||
1. [Stack Overflow](http://stackoverflow.com/questions/tagged/antd)
|
||||
2. [Segment Fault](https://segmentfault.com/t/antd)(中文)
|
||||
3. [Gitter](https://gitter.im/ant-design/ant-design)
|
||||
|
||||
不是用上面的链接创建的 issue 会被立即关闭。
|
||||
如果是报告 bug,请按照下列格式书写,并务必提供复现步骤,否则恕难解决,感谢您的支持。
|
||||
-->
|
||||
|
||||
#### 发生问题的环境是:
|
||||
|
||||
<!-- 务必提供 -->
|
||||
|
||||
- antd 版本:
|
||||
- 操作系统及其版本:
|
||||
- 浏览器及其版本:
|
||||
|
||||
#### 您做了什么?请提供尽可能详细的重现步骤。
|
||||
|
||||
<!-- 如:引入 antd 了 Button -->
|
||||
|
||||
#### 您期待的结果是:
|
||||
|
||||
<!-- 如:像官网一样正常显示 -->
|
||||
|
||||
#### 实际上的结果是:
|
||||
|
||||
<!-- 如:样式错位了,最好提供截图 -->
|
||||
|
||||
#### 可重现的在线演示
|
||||
|
||||
<!-- 请修改并 Fork http://codepen.io/benjycui/pen/KgPZrE?editors=001 -->
|
||||
|
||||
@@ -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 会被立即关闭。
|
||||
24
.github/PULL_REQUEST_TEMPLATE.md
vendored
24
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,22 +1,8 @@
|
||||
First of all, thank you for your contribution! :-)
|
||||
First of all, thanks for your contribution! :-)
|
||||
|
||||
Please makes sure that these checkboxes are checked before submitting your pull request, thank you!
|
||||
Please makes sure these boxes are checked before submitting your PR, thank you!
|
||||
|
||||
* [ ] Make sure that you propose pull request to right branch: bugfix for `master`, feature for branch `feature`.
|
||||
* [ ] Make sure that you follow antd's [code convention](https://github.com/ant-design/ant-design/wiki/Code-convention-for-antd).
|
||||
* [ ] Make sure 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 pull request to keep commit history clear.
|
||||
* [ ] Add some descriptions and refer relative issues for you pull request.
|
||||
|
||||
Extra checklist:
|
||||
|
||||
**if** *isBugFix* **:**
|
||||
|
||||
* [ ] Make sure that you add at least one unit test for the bug which you had fixed.
|
||||
|
||||
**elif** *isNewFeature* **:**
|
||||
|
||||
* [ ] 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.
|
||||
* [ ] Rebase before creating a PR to keep commit history clear.
|
||||
* [ ] Add some descriptions and refer relative issues for you PR.
|
||||
|
||||
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
|
||||
15
.gitignore
vendored
15
.gitignore
vendored
@@ -15,7 +15,6 @@ Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
*.log
|
||||
*.log.*
|
||||
*.json.gzip
|
||||
node_modules/
|
||||
.buildpath
|
||||
@@ -26,20 +25,8 @@ _site
|
||||
_data
|
||||
dist
|
||||
/lib
|
||||
/es
|
||||
elasticsearch-*
|
||||
config/base.yaml
|
||||
/.vscode/
|
||||
/coverage
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
components/**/*.js
|
||||
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
|
||||
/.vscode/
|
||||
|
||||
36
.jest.js
36
.jest.js
@@ -1,36 +0,0 @@
|
||||
const libDir = process.env.LIB_DIR;
|
||||
|
||||
const transformIgnorePatterns = [
|
||||
'/dist/',
|
||||
'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'],
|
||||
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',
|
||||
},
|
||||
testRegex: `${libDir === 'dist' ? 'demo' : '.*'}\\.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',
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
// jest config for server render environment
|
||||
module.exports = {
|
||||
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',
|
||||
},
|
||||
testRegex: 'demo\\.test\\.js$',
|
||||
testEnvironment: 'node',
|
||||
snapshotSerializers: ['enzyme-to-json/serializer'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfigFile: './tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
};
|
||||
21
.lesshintrc
Normal file
21
.lesshintrc
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"propertyOrdering": false,
|
||||
"hexLength": "short",
|
||||
"stringQuotes": false,
|
||||
"decimalZero": false,
|
||||
"importantRule": false,
|
||||
"zeroUnit": "no_unit",
|
||||
"qualifyingElement": false,
|
||||
"duplicateProperty": false,
|
||||
"importPath": false,
|
||||
"finalNewline": false,
|
||||
"newlineAfterBlock": false,
|
||||
"maxCharPerLine": false,
|
||||
"excludedFiles": [
|
||||
"components/layout/style/mixin.less",
|
||||
"components/style/core/base.less",
|
||||
"components/style/core/iconfont.less",
|
||||
"components/style/core/normalize.less",
|
||||
"components/style/mixins/compatibility.less"
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
23
.stylelintrc
23
.stylelintrc
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
|
||||
"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,
|
||||
"unit-no-unknown": null,
|
||||
"value-list-max-empty-lines": null,
|
||||
"font-family-no-missing-generic-family-keyword": null,
|
||||
"no-descending-specificity": null
|
||||
}
|
||||
}
|
||||
27
.travis.yml
27
.travis.yml
@@ -3,29 +3,4 @@ sudo: false
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- 11
|
||||
|
||||
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
|
||||
|
||||
script:
|
||||
- scripts/travis-script.sh
|
||||
- "6"
|
||||
|
||||
547
AUTHORS.txt
547
AUTHORS.txt
@@ -1,654 +1,107 @@
|
||||
17073025 <17073025@cnsuning.com>
|
||||
282159468 <282159468@qq.com>
|
||||
778758944 <778758944@qq.com>
|
||||
Aaron Planell López <aaronplanell@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>
|
||||
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>
|
||||
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>
|
||||
edgji <j.edgji@gmail.com>
|
||||
elios <elios264@hotmail.com>
|
||||
elrrrrrrr <elrrrrrrr@gmail.com>
|
||||
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>
|
||||
柚子男 <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>
|
||||
|
||||
1516
CHANGELOG.en-US.md
1516
CHANGELOG.en-US.md
File diff suppressed because it is too large
Load Diff
1948
CHANGELOG.zh-CN.md
1948
CHANGELOG.zh-CN.md
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at xingmin.zhu@alipay.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## 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].
|
||||
|
||||
[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
|
||||
|
||||
132
README-zh_CN.md
132
README-zh_CN.md
@@ -1,58 +1,33 @@
|
||||
<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>
|
||||
|
||||
<div align="center">
|
||||
# Ant Design
|
||||
[](https://travis-ci.org/ant-design/ant-design)
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](https://npmjs.org/package/antd)
|
||||
[](https://cdnjs.com/libraries/antd)
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
一套企业级的 UI 设计语言和 React 实现。
|
||||
|
||||
[](https://circleci.com/gh/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/alerts/)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/context:javascript)
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
## 特性
|
||||
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](http://npmjs.com/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)
|
||||
[](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 组件。
|
||||
- 提炼和服务企业级中后台产品的交互语言和视觉风格。
|
||||
- [React Component](http://react-component.github.io/badgeboard/) 基础上精心封装的高质量 UI 组件。
|
||||
- 使用 TypeScript 构建,提供完整的类型定义文件。
|
||||
- 全链路开发和设计工具体系。
|
||||
- 基于 npm + webpack + babel + [dora](https://github.com/dora-js/dora) + [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
|
||||
|
||||
## 📦 安装
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm install antd --save
|
||||
npm install antd
|
||||
```
|
||||
|
||||
## 🔨 示例
|
||||
## 示例
|
||||
|
||||
```jsx
|
||||
import { DatePicker } from 'antd';
|
||||
@@ -65,60 +40,47 @@ 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-plugin-import](https://github.com/ant-design/babel-plugin-import)。
|
||||
|
||||
### TypeScript
|
||||
|
||||
参考 [在 TypeScript 中使用](https://ant.design/docs/react/use-in-typescript-cn)
|
||||
## 浏览器支持
|
||||
|
||||
## 🌍 国际化
|
||||
现代浏览器和 IE9 及以上。
|
||||
|
||||
参考 [国际化文档](http://ant.design/docs/react/i18n-cn)。
|
||||
> [IE8 issues](https://github.com/xcatliu/react-ie8)
|
||||
|
||||
## 🔗 链接
|
||||
## TypeScript
|
||||
|
||||
- [首页](http://ant.design/)
|
||||
- [组件库](http://ant.design/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [更新日志](CHANGELOG.en-US.md)
|
||||
- [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
|
||||
- [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
|
||||
- [定制主题](http://ant.design/docs/react/customize-theme-cn)
|
||||
tsconfig.json
|
||||
|
||||
## ⌨️ 本地开发
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:ant-design/ant-design.git
|
||||
$ cd ant-design
|
||||
$ npm install
|
||||
$ npm start
|
||||
```
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"jsx": "preserve",
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
打开浏览器访问 http://127.0.0.1:8001 ,更多[本地开发文档](https://github.com/ant-design/ant-design/wiki/Development)。
|
||||
## 链接
|
||||
|
||||
## 🤝 参与共建 [](http://makeapullrequest.com)
|
||||
- [首页](http://ant.design/)
|
||||
- [React 实现](http://ant.design/docs/react/introduce)
|
||||
- [修改记录](CHANGELOG.zh-CN.md)
|
||||
- [开发脚手架](https://github.com/ant-design/antd-init/)
|
||||
- [开发工具文档](http://ant-tool.github.io/)
|
||||
- [React 基础组件](http://react-component.github.io/)
|
||||
- [移动端组件](http://mobile.ant.design)
|
||||
- [React 代码规范](https://github.com/react-component/react-component.github.io/blob/master/docs/zh-cn/component-code-style.md)
|
||||
- [组件设计原则](https://github.com/react-component/react-component.github.io/blob/master/docs/zh-cn/component-design.md)
|
||||
- [网站和组件开发说明](https://github.com/ant-design/ant-design/wiki/%E7%BD%91%E7%AB%99%E5%92%8C%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91%E8%AF%B4%E6%98%8E)
|
||||
- [版本发布手册](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
|
||||
- [社区贡献脚手架和范例](https://github.com/ant-design/ant-design/issues/129)
|
||||
- [常见问题](https://github.com/ant-design/ant-design/wiki/FAQ)
|
||||
- [CodePen 模板](http://codepen.io/benjycui/pen/KgPZrE?editors=001)
|
||||
- [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
|
||||
|
||||
请参考[贡献指南](https://ant.design/docs/react/contributing-cn).
|
||||
## 如何贡献
|
||||
|
||||
> 强烈推荐阅读 [《提问的智慧》](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)
|
||||
|
||||
## 社区互助
|
||||
|
||||
如果您在使用的过程中碰到问题,可以通过下面几个途径寻求帮助,同时我们也鼓励资深用户通过下面的途径给新人提供帮助。
|
||||
|
||||
通过 Stack Overflow 或者 Segment Fault 提问时,建议加上 `antd` 标签。
|
||||
|
||||
1. [Stack Overflow](http://stackoverflow.com/questions/tagged/antd)(英文)
|
||||
2. [Segment Fault](https://segmentfault.com/t/antd)(中文)
|
||||
3. [](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
我们欢迎任何形式的贡献,有任何建议或意见您可以进行 [Pull Request](https://github.com/ant-design/ant-design/pulls),或者给我们 [提问](https://github.com/ant-design/ant-design/issues)。
|
||||
|
||||
146
README.md
146
README.md
@@ -1,58 +1,35 @@
|
||||
<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>
|
||||
|
||||
<div align="center">
|
||||
# Ant Design
|
||||
[](https://travis-ci.org/ant-design/ant-design)
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](https://npmjs.org/package/antd)
|
||||
[](https://cdnjs.com/libraries/antd)
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](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.
|
||||
|
||||
[](https://circleci.com/gh/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/alerts/)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/context:javascript)
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
## Features
|
||||
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](http://npmjs.com/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)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
- An enterprise-class design language and high quality UI.
|
||||
- Graceful UI components out of the box, base on [React Component](http://react-component.github.io/badgeboard/).
|
||||
- Writen in TypeScript with complete define types.
|
||||
- A npm + webpack + babel + [dora](https://github.com/dora-js/dora) + [dva](https://github.com/dvajs/dva) development framework.
|
||||
|
||||
</div>
|
||||
|
||||
[](http://ant.design)
|
||||
|
||||
English | [简体中文](./README-zh_CN.md)
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- An enterprise-class UI design system 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.
|
||||
|
||||
## 🖥 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
|
||||
|
||||
## 📦 Install
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install antd --save
|
||||
npm install antd
|
||||
```
|
||||
|
||||
## 🔨 Usage
|
||||
## Usage
|
||||
|
||||
### Use prebuilt bundle
|
||||
|
||||
```jsx
|
||||
import { DatePicker } from 'antd';
|
||||
@@ -65,49 +42,70 @@ 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
|
||||
|
||||
### TypeScript
|
||||
- Use [babel-plugin-import](https://github.com/ant-design/babel-plugin-import) (Recommended)
|
||||
|
||||
See [Use in TypeScript](https://ant.design/docs/react/use-in-typescript).
|
||||
```js
|
||||
// .babelrc
|
||||
{
|
||||
"plugins": [["import", { libraryName: "antd", style: "css" }]]
|
||||
}
|
||||
```
|
||||
|
||||
## 🌍 Internationalization
|
||||
Then you can import components from antd directly.
|
||||
|
||||
See [i18n](http://ant.design/docs/react/i18n).
|
||||
```jsx
|
||||
// import js and css modularly, parsed by babel-plugin-import
|
||||
import { DatePicker } from 'antd';
|
||||
```
|
||||
|
||||
## 🔗 Links
|
||||
- Manually import
|
||||
|
||||
- [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)
|
||||
- [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
|
||||
- [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
|
||||
- [Customize Theme](http://ant.design/docs/react/customize-theme)
|
||||
```jsx
|
||||
import DatePicker from 'antd/lib/date-picker'; // just for js
|
||||
import 'antd/lib/date-picker/style/css'; // with style
|
||||
```
|
||||
|
||||
## ⌨️ Development
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:ant-design/ant-design.git
|
||||
$ cd ant-design
|
||||
$ npm install
|
||||
$ npm start
|
||||
## Browser Support
|
||||
|
||||
Normal browsers and Internet Explorer 9+.
|
||||
|
||||
> [IE8 issues](https://github.com/xcatliu/react-ie8)
|
||||
|
||||
## TypeScript
|
||||
|
||||
tsconfig.json
|
||||
|
||||
```
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"jsx": "preserve",
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Open your browser and visit http://127.0.0.1:8001 , see more at [Development](https://github.com/ant-design/ant-design/wiki/Development).
|
||||
## Links
|
||||
|
||||
## 🤝 Contributing [](http://makeapullrequest.com)
|
||||
- [Home page](http://ant.design/)
|
||||
- [UI library](http://ant.design/docs/react/introduce)
|
||||
- [ChangeLog](CHANGELOG.en-US.md)
|
||||
- [Scaffold tool](https://github.com/ant-design/antd-init/)
|
||||
- [Development tool](http://ant-tool.github.io/)
|
||||
- [React components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
- [React style guide](https://github.com/react-component/react-component.github.io/blob/master/docs/zh-cn/component-code-style.md)
|
||||
- [React component design guide](https://github.com/react-component/react-component.github.io/blob/master/docs/zh-cn/component-design.md)
|
||||
- [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)
|
||||
- [Boilerplates](https://github.com/ant-design/ant-design/issues/129)
|
||||
- [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)
|
||||
|
||||
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! :)
|
||||
|
||||
[](https://issuehunt.io/repos/34526884)
|
||||
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 a [GitHub issue](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instruction](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`antd exports modules correctly 1`] = `
|
||||
Array [
|
||||
"Affix",
|
||||
"Anchor",
|
||||
"AutoComplete",
|
||||
"Alert",
|
||||
"Avatar",
|
||||
"BackTop",
|
||||
"Badge",
|
||||
"Breadcrumb",
|
||||
"Button",
|
||||
"Calendar",
|
||||
"Card",
|
||||
"Collapse",
|
||||
"Carousel",
|
||||
"Cascader",
|
||||
"Checkbox",
|
||||
"Col",
|
||||
"Comment",
|
||||
"ConfigProvider",
|
||||
"DatePicker",
|
||||
"Divider",
|
||||
"Dropdown",
|
||||
"Drawer",
|
||||
"Form",
|
||||
"Icon",
|
||||
"Input",
|
||||
"InputNumber",
|
||||
"Layout",
|
||||
"List",
|
||||
"LocaleProvider",
|
||||
"message",
|
||||
"Menu",
|
||||
"Modal",
|
||||
"notification",
|
||||
"Pagination",
|
||||
"Popconfirm",
|
||||
"Popover",
|
||||
"Progress",
|
||||
"Radio",
|
||||
"Rate",
|
||||
"Row",
|
||||
"Select",
|
||||
"Skeleton",
|
||||
"Slider",
|
||||
"Spin",
|
||||
"Steps",
|
||||
"Switch",
|
||||
"Table",
|
||||
"Transfer",
|
||||
"Tree",
|
||||
"TreeSelect",
|
||||
"Tabs",
|
||||
"Tag",
|
||||
"TimePicker",
|
||||
"Timeline",
|
||||
"Tooltip",
|
||||
"Mention",
|
||||
"Upload",
|
||||
"version",
|
||||
]
|
||||
`;
|
||||
@@ -1,21 +0,0 @@
|
||||
const OLD_NODE_ENV = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = 'development';
|
||||
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
const antd = require('..');
|
||||
|
||||
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,131 +0,0 @@
|
||||
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(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('throttle function should work', () => {
|
||||
const callback = jest.fn();
|
||||
const throttled = throttleByAnimationFrame(callback);
|
||||
expect(callback).not.toBeCalled();
|
||||
|
||||
throttled();
|
||||
throttled();
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(callback).toBeCalled();
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('throttle function should be canceled', () => {
|
||||
const callback = jest.fn();
|
||||
const throttled = throttleByAnimationFrame(callback);
|
||||
|
||||
throttled();
|
||||
throttled.cancel();
|
||||
|
||||
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;
|
||||
}, {});
|
||||
}
|
||||
10
components/_util/getLocale.tsx
Normal file
10
components/_util/getLocale.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import assign from 'object-assign';
|
||||
|
||||
export default function getLocale(props, context, componentName, getDefaultLocale) {
|
||||
const locale = context && context.antLocale && context.antLocale[componentName] ?
|
||||
context.antLocale[componentName] : getDefaultLocale();
|
||||
|
||||
const result = assign({}, locale, props.locale);
|
||||
result.lang = assign({}, locale.lang, props.locale.lang);
|
||||
return result;
|
||||
}
|
||||
12
components/_util/getRequestAnimationFrame.tsx
Normal file
12
components/_util/getRequestAnimationFrame.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function getRequestAnimationFrame() {
|
||||
if (typeof window === 'undefined') {
|
||||
return () => {};
|
||||
}
|
||||
if (window.requestAnimationFrame) {
|
||||
return window.requestAnimationFrame;
|
||||
}
|
||||
const prefix = ['moz', 'ms', 'webkit'].filter(key => `${key}RequestAnimationFrame` in window)[0];
|
||||
return prefix
|
||||
? window[`${prefix}RequestAnimationFrame`]
|
||||
: callback => setTimeout(callback, 1000 / 60);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1,12 +0,0 @@
|
||||
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 = <T extends number>(value: any): value is T => {
|
||||
return !isNaN(parseFloat(value)) && isFinite(value);
|
||||
};
|
||||
|
||||
export default isNumeric;
|
||||
@@ -1,48 +1,34 @@
|
||||
import cssAnimation from 'css-animation';
|
||||
import raf from 'raf';
|
||||
|
||||
function animate(node: HTMLElement, show: boolean, done: () => void) {
|
||||
let height: number;
|
||||
let requestAnimationFrameId: number;
|
||||
function animate(node, show, done) {
|
||||
let height;
|
||||
return cssAnimation(node, 'ant-motion-collapse', {
|
||||
start() {
|
||||
if (!show) {
|
||||
node.style.height = `${node.offsetHeight}px`;
|
||||
node.style.opacity = '1';
|
||||
} else {
|
||||
height = node.offsetHeight;
|
||||
node.style.height = '0px';
|
||||
node.style.opacity = '0';
|
||||
node.style.height = 0;
|
||||
}
|
||||
},
|
||||
active() {
|
||||
if (requestAnimationFrameId) {
|
||||
raf.cancel(requestAnimationFrameId);
|
||||
}
|
||||
requestAnimationFrameId = raf(() => {
|
||||
node.style.height = `${show ? height : 0}px`;
|
||||
node.style.opacity = show ? '1' : '0';
|
||||
});
|
||||
node.style.height = `${show ? height : 0}px`;
|
||||
},
|
||||
end() {
|
||||
if (requestAnimationFrameId) {
|
||||
raf.cancel(requestAnimationFrameId);
|
||||
}
|
||||
node.style.height = '';
|
||||
node.style.opacity = '';
|
||||
done();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
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(id: number) {
|
||||
raf.cancel(ids[id]);
|
||||
delete ids[id];
|
||||
};
|
||||
12
components/_util/splitObject.tsx
Normal file
12
components/_util/splitObject.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function splitObject(obj, parts): Array<any> {
|
||||
const left = {};
|
||||
const right = {};
|
||||
Object.keys(obj).forEach((k) => {
|
||||
if (parts.indexOf(k) !== -1) {
|
||||
left[k] = obj[k];
|
||||
} else {
|
||||
right[k] = obj[k];
|
||||
}
|
||||
});
|
||||
return [left, right];
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import raf from 'raf';
|
||||
|
||||
export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
|
||||
let requestId: number | null;
|
||||
|
||||
const later = (args: any[]) => () => {
|
||||
requestId = null;
|
||||
fn(...args);
|
||||
};
|
||||
|
||||
const throttled = (...args: any[]) => {
|
||||
if (requestId == null) {
|
||||
requestId = raf(later(args));
|
||||
}
|
||||
};
|
||||
|
||||
(throttled as any).cancel = () => raf.cancel(requestId!);
|
||||
|
||||
return throttled;
|
||||
}
|
||||
|
||||
export function throttleByAnimationFrameDecorator() {
|
||||
return function(target: any, key: string, descriptor: any) {
|
||||
const fn = descriptor.value;
|
||||
let definingProperty = false;
|
||||
return {
|
||||
configurable: true,
|
||||
get() {
|
||||
if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
const boundFn = throttleByAnimationFrame(fn.bind(this));
|
||||
definingProperty = true;
|
||||
Object.defineProperty(this, key, {
|
||||
value: boundFn,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
definingProperty = false;
|
||||
return boundFn;
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export default function triggerEvent(el: Element, type: string) {
|
||||
if ('createEvent' in document) {
|
||||
// modern browsers, IE9+
|
||||
const e = document.createEvent('HTMLEvents');
|
||||
e.initEvent(type, false, true);
|
||||
el.dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
@@ -1,9 +0,0 @@
|
||||
import warning from 'warning';
|
||||
|
||||
const warned: { [msg: string]: boolean } = {};
|
||||
export default (valid: boolean, message: string): void => {
|
||||
if (!valid && !warned[message]) {
|
||||
warning(false, message);
|
||||
warned[message] = true;
|
||||
}
|
||||
};
|
||||
@@ -1,175 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import TransitionEvents from 'css-animation/lib/Event';
|
||||
import raf from '../_util/raf';
|
||||
|
||||
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;
|
||||
|
||||
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.removeAttribute(attributeName);
|
||||
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'
|
||||
) {
|
||||
extraNode.style.borderColor = waveColor;
|
||||
styleForPesudo.innerHTML = `[ant-click-animating-without-extra-node]: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.removeAttribute(attributeName);
|
||||
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;
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Affix from '..';
|
||||
import Button from '../../button';
|
||||
|
||||
const events = {};
|
||||
|
||||
class AffixMounter extends React.Component {
|
||||
componentDidMount() {
|
||||
this.container.addEventListener = jest.fn().mockImplementation((event, cb) => {
|
||||
events[event] = cb;
|
||||
});
|
||||
}
|
||||
|
||||
getTarget = () => this.container;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: 100,
|
||||
overflowY: 'scroll',
|
||||
}}
|
||||
ref={node => {
|
||||
this.container = node;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="background"
|
||||
style={{
|
||||
paddingTop: 60,
|
||||
height: 300,
|
||||
}}
|
||||
>
|
||||
<Affix
|
||||
target={() => this.container}
|
||||
ref={ele => {
|
||||
this.affix = ele;
|
||||
}}
|
||||
{...this.props}
|
||||
>
|
||||
<Button type="primary">Fixed at the top of container</Button>
|
||||
</Affix>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
describe('Affix Render', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
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') });
|
||||
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'),
|
||||
});
|
||||
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'),
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -1,77 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/affix/demo/basic.md correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Affix top
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Affix bottom
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/on-change.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
120px to affix top
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/target.md correctly 1`] = `
|
||||
<div
|
||||
class="scrollable-container"
|
||||
>
|
||||
<div
|
||||
class="background"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Fixed at the top of container
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,3 +0,0 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('affix');
|
||||
@@ -16,44 +16,9 @@ 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(
|
||||
<Affix>
|
||||
<Button type="primary">Affix top</Button>
|
||||
</Affix>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
24
components/affix/demo/bottom.md
Normal file
24
components/affix/demo/bottom.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
zh-CN: 下方固定
|
||||
en-US: Bottom
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
固定在屏幕下方。
|
||||
|
||||
## en-US
|
||||
|
||||
Affix to bottom.
|
||||
|
||||
````jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<Affix offsetBottom={20}>
|
||||
<Button type="primary">20px to affix bottom</Button>
|
||||
</Affix>
|
||||
, mountNode);
|
||||
````
|
||||
24
components/affix/demo/offset.md
Normal file
24
components/affix/demo/offset.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
order: 1
|
||||
title:
|
||||
zh-CN: 偏移
|
||||
en-US: Offset
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
达到一定的偏移量才触发。
|
||||
|
||||
## en-US
|
||||
|
||||
Affix element according to offset value.
|
||||
|
||||
````jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<Affix offsetTop={75}>
|
||||
<Button type="primary">75px to affix top</Button>
|
||||
</Affix>
|
||||
, mountNode);
|
||||
````
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 1
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 固定状态改变的回调
|
||||
en-US: Callback
|
||||
@@ -19,7 +19,6 @@ import { Affix, Button } from 'antd';
|
||||
ReactDOM.render(
|
||||
<Affix offsetTop={120} onChange={affixed => console.log(affixed)}>
|
||||
<Button>120px to affix top</Button>
|
||||
</Affix>,
|
||||
mountNode
|
||||
);
|
||||
</Affix>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 2
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 滚动容器
|
||||
en-US: Container to scroll.
|
||||
@@ -11,38 +11,27 @@ title:
|
||||
|
||||
## en-US
|
||||
|
||||
Set a `target` for 'Affix', which is listen to scroll event of target element (default is `window`).
|
||||
Set a `target` for 'Affix', which is listen to scroll event of target element (default is `window`).
|
||||
|
||||
````jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
|
||||
class Demo extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="scrollable-container" ref={(node) => { this.container = node; }}>
|
||||
<div className="background">
|
||||
<Affix target={() => this.container}>
|
||||
<Button type="primary">
|
||||
Fixed at the top of container
|
||||
</Button>
|
||||
const Demo = () => {
|
||||
return (
|
||||
<div style={{ height: 100, overflow: 'hidden' }}>
|
||||
<div style={{ height: '100%', overflowY: 'scroll' }} id="affix-target">
|
||||
<div style={{ height: 300, backgroundImage: 'url(https://zos.alipayobjects.com/rmsportal/RmjwQiJorKyobvI.jpg)' }}>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Affix target={() => document.getElementById('affix-target')} offsetTop={20}>
|
||||
<Button type="primary">Fixed at the top of container</Button>
|
||||
</Affix>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
````
|
||||
|
||||
<style>
|
||||
#components-affix-demo-target .scrollable-container {
|
||||
height: 100px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#components-affix-demo-target .background {
|
||||
padding-top: 60px;
|
||||
height: 300px;
|
||||
background-image: url('https://zos.alipayobjects.com/rmsportal/RmjwQiJorKyobvI.jpg');
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
---
|
||||
category: Components
|
||||
type: Navigation
|
||||
type: Other
|
||||
title: Affix
|
||||
---
|
||||
|
||||
Make an element stick to viewport.
|
||||
Make an element sticky to viewport.
|
||||
|
||||
## When To Use
|
||||
|
||||
When user browses a long web page, some content need to stick to the viewport. This is common for menus and actions.
|
||||
When user browses a long web page, some content need to sticky to viewport. It is common for menus and actions.
|
||||
|
||||
Please note that Affix should not cover other content on the page, especially when the size of the viewport is small.
|
||||
Please note that Affix should not cover other content in page, especially when the size of viewport is small.
|
||||
|
||||
## API
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| 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 |
|
||||
| target | specifies the scrollable area dom node | () => HTMLElement | () => window |
|
||||
| onChange | Callback for when affix state is changed | Function(affixed) | - |
|
||||
| Property | Description | Type | Default |
|
||||
|--------------|-----------------------|----------|--------------|
|
||||
| offsetTop | Pixels to offset from top when calculating position of scroll | Number | 0 |
|
||||
| offsetBottom | Pixels to offset from bottom when calculating position of scroll | Number | - |
|
||||
| onChange | Callback when affix state is changed | Function(affixed) | - |
|
||||
|
||||
**Note:** Children of `Affix` can not be `position: absolute`, but you can set `Affix` as `position: absolute`:
|
||||
|
||||
|
||||
@@ -1,20 +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 addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import classNames from 'classnames';
|
||||
import shallowequal from 'shallowequal';
|
||||
import omit from 'omit.js';
|
||||
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);
|
||||
|
||||
@@ -26,18 +24,19 @@ 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,
|
||||
width: elemRect.width,
|
||||
height: elemRect.height,
|
||||
top: elemRect.top - targetRect.top +
|
||||
scrollTop - clientTop,
|
||||
left: elemRect.left - targetRect.left +
|
||||
scrollLeft - clientLeft,
|
||||
};
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
function getDefaultTarget() {
|
||||
return typeof window !== 'undefined' ? window : null;
|
||||
}
|
||||
return typeof window !== 'undefined' ?
|
||||
window : null;
|
||||
};
|
||||
|
||||
// Affix
|
||||
export interface AffixProps {
|
||||
@@ -52,42 +51,32 @@ export interface AffixProps {
|
||||
/** 固定状态改变时触发的回调函数 */
|
||||
onChange?: (affixed?: boolean) => void;
|
||||
/** 设置 Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
|
||||
target?: () => Window | HTMLElement | null;
|
||||
target?: () => Window | HTMLElement;
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
export interface AffixState {
|
||||
affixStyle: React.CSSProperties | undefined;
|
||||
placeholderStyle: React.CSSProperties | undefined;
|
||||
}
|
||||
|
||||
export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
export default class Affix extends React.Component<AffixProps, any> {
|
||||
static propTypes = {
|
||||
offsetTop: PropTypes.number,
|
||||
offsetBottom: PropTypes.number,
|
||||
target: PropTypes.func,
|
||||
offsetTop: React.PropTypes.number,
|
||||
offsetBottom: React.PropTypes.number,
|
||||
target: React.PropTypes.func,
|
||||
};
|
||||
|
||||
state: AffixState = {
|
||||
affixStyle: undefined,
|
||||
placeholderStyle: undefined,
|
||||
scrollEvent: any;
|
||||
resizeEvent: any;
|
||||
refs: {
|
||||
fixedNode: HTMLElement;
|
||||
};
|
||||
|
||||
private timeout: number;
|
||||
private eventHandlers: Record<string, any> = {};
|
||||
private fixedNode: HTMLElement;
|
||||
private placeholderNode: HTMLElement;
|
||||
private readonly events = [
|
||||
'resize',
|
||||
'scroll',
|
||||
'touchstart',
|
||||
'touchmove',
|
||||
'touchend',
|
||||
'pageshow',
|
||||
'load',
|
||||
];
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
affixStyle: null,
|
||||
placeholderStyle: null,
|
||||
};
|
||||
}
|
||||
|
||||
setAffixStyle(e: Event, affixStyle: React.CSSProperties | null) {
|
||||
setAffixStyle(e, affixStyle) {
|
||||
const { onChange = noop, target = getDefaultTarget } = this.props;
|
||||
const originalAffixStyle = this.state.affixStyle;
|
||||
const isWindow = target() === window;
|
||||
@@ -97,53 +86,38 @@ 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(e, placeholderStyle) {
|
||||
const originalPlaceholderStyle = this.state.placeholderStyle;
|
||||
if (e.type === 'resize') {
|
||||
return;
|
||||
}
|
||||
if (shallowequal(placeholderStyle, originalPlaceholderStyle)) {
|
||||
return;
|
||||
}
|
||||
this.setState({ placeholderStyle: placeholderStyle as React.CSSProperties });
|
||||
this.setState({ placeholderStyle });
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
@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 = {
|
||||
@@ -162,134 +136,83 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
const targetRect = getTargetRect(targetNode);
|
||||
const targetInnerHeight =
|
||||
(targetNode as Window).innerHeight || (targetNode as HTMLElement).clientHeight;
|
||||
if (scrollTop > elemOffset.top - (offsetTop as number) && offsetMode.top) {
|
||||
if (scrollTop > elemOffset.top - offsetTop && 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,
|
||||
left: targetRect.left + elemOffset.left,
|
||||
width,
|
||||
width: affixNode.offsetWidth,
|
||||
});
|
||||
this.setPlaceholderStyle({
|
||||
width,
|
||||
height: elemSize.height,
|
||||
this.setPlaceholderStyle(e, {
|
||||
width: affixNode.offsetWidth,
|
||||
height: affixNode.offsetHeight,
|
||||
});
|
||||
} else if (
|
||||
scrollTop < elemOffset.top + elemSize.height + (offsetBottom as number) - targetInnerHeight &&
|
||||
offsetMode.bottom
|
||||
scrollTop < elemOffset.top + elemSize.height + offsetBottom - targetInnerHeight &&
|
||||
offsetMode.bottom
|
||||
) {
|
||||
// Fixed Bottom
|
||||
const targetBottomOffet = targetNode === window ? 0 : window.innerHeight - targetRect.bottom;
|
||||
const width = elemOffset.width;
|
||||
const targetBottomOffet = targetNode === window ? 0 : (window.innerHeight - targetRect.bottom);
|
||||
this.setAffixStyle(e, {
|
||||
position: 'fixed',
|
||||
bottom: targetBottomOffet + (offsetBottom as number),
|
||||
bottom: targetBottomOffet + offsetBottom,
|
||||
left: targetRect.left + elemOffset.left,
|
||||
width,
|
||||
width: affixNode.offsetWidth,
|
||||
});
|
||||
this.setPlaceholderStyle({
|
||||
width,
|
||||
height: elemOffset.height,
|
||||
this.setPlaceholderStyle(e, {
|
||||
width: affixNode.offsetWidth,
|
||||
height: affixNode.offsetHeight,
|
||||
});
|
||||
} else {
|
||||
const { affixStyle } = this.state;
|
||||
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);
|
||||
this.setAffixStyle(e, null);
|
||||
this.setPlaceholderStyle(e, null);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const target = this.props.target || getDefaultTarget;
|
||||
// Wait for parent component ref has its value
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setTargetEventListeners(target);
|
||||
// Mock Event object.
|
||||
this.updatePosition({} as Event);
|
||||
});
|
||||
this.setTargetEventListeners(target);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: AffixProps) {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.target !== nextProps.target) {
|
||||
this.clearEventListeners();
|
||||
this.setTargetEventListeners(nextProps.target!);
|
||||
this.clearScrollEventListeners();
|
||||
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({});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearEventListeners();
|
||||
clearTimeout(this.timeout);
|
||||
(this.updatePosition as any).cancel();
|
||||
this.clearScrollEventListeners();
|
||||
}
|
||||
|
||||
setTargetEventListeners(getTarget: () => HTMLElement | Window | null) {
|
||||
setTargetEventListeners(getTarget) {
|
||||
const target = getTarget();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
this.clearEventListeners();
|
||||
|
||||
this.events.forEach(eventName => {
|
||||
this.eventHandlers[eventName] = addEventListener(target, eventName, this.updatePosition);
|
||||
});
|
||||
this.scrollEvent = addEventListener(target, 'scroll', this.updatePosition);
|
||||
this.resizeEvent = addEventListener(target, 'resize', this.updatePosition);
|
||||
}
|
||||
|
||||
clearEventListeners() {
|
||||
this.events.forEach(eventName => {
|
||||
const handler = this.eventHandlers[eventName];
|
||||
if (handler && handler.remove) {
|
||||
handler.remove();
|
||||
clearScrollEventListeners() {
|
||||
['scrollEvent', 'resizeEvent'].forEach((name) => {
|
||||
if (this[name]) {
|
||||
this[name].remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
saveFixedNode = (node: HTMLDivElement) => {
|
||||
this.fixedNode = node;
|
||||
};
|
||||
|
||||
savePlaceholderNode = (node: HTMLDivElement) => {
|
||||
this.placeholderNode = node;
|
||||
};
|
||||
|
||||
render() {
|
||||
const className = classNames({
|
||||
[this.props.prefixCls || 'ant-affix']: this.state.affixStyle,
|
||||
});
|
||||
|
||||
const props = omit(this.props, [
|
||||
'prefixCls',
|
||||
'offsetTop',
|
||||
'offsetBottom',
|
||||
'target',
|
||||
'onChange',
|
||||
]);
|
||||
const placeholderStyle = { ...this.state.placeholderStyle, ...this.props.style };
|
||||
const props = omit(this.props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target']);
|
||||
|
||||
return (
|
||||
<div {...props} style={placeholderStyle} ref={this.savePlaceholderNode}>
|
||||
<div className={className} ref={this.saveFixedNode} style={this.state.affixStyle}>
|
||||
<div {...props} style={this.state.placeholderStyle}>
|
||||
<div className={className} ref="fixedNode" style={this.state.affixStyle}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 固钉
|
||||
type: 导航
|
||||
type: Other
|
||||
title: Affix
|
||||
---
|
||||
|
||||
@@ -15,12 +15,12 @@ title: Affix
|
||||
|
||||
## API
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | number | |
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | |
|
||||
| target | 设置 `Affix` 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | () => HTMLElement | () => window |
|
||||
| onChange | 固定状态改变时触发的回调函数 | Function(affixed) | 无 |
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
|-------------|----------------|--------------------|--------------|
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | Number | |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | Number | |
|
||||
| target | 设置 `Affix` 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | Function | () => window |
|
||||
| onChange | 固定状态改变时触发的回调函数 | Function(affixed) | 无 |
|
||||
|
||||
**注意:**`Affix` 内的元素不要使用绝对定位,如需要绝对定位的效果,可以直接设置 `Affix` 为绝对定位:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../style/themes/default';
|
||||
@import "../../style/themes/default";
|
||||
|
||||
.@{ant-prefix}-affix {
|
||||
position: fixed;
|
||||
|
||||
@@ -1,940 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-banner"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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"
|
||||
>
|
||||
Warning text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-banner ant-alert-closable"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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"
|
||||
>
|
||||
Very long warning text warning text text text text text text text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<a
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
<br />
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-banner"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Warning text without icon
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-banner"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Error text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/basic.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Success Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-closable"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<a
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Error Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Error Description Error Description Error Description Error Description Error Description Error Description
|
||||
</span>
|
||||
<a
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon ant-alert-closable"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Info Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<a
|
||||
class="ant-alert-close-icon"
|
||||
>
|
||||
Close Now
|
||||
</a>
|
||||
</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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
class="ant-alert ant-alert-success ant-alert-with-description ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Success Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Success Description Success Description Success Description
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Info Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Info Description Info Description Info Description Info Description
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-with-description ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Warning Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Warning Description Warning Description Warning Description Warning Description
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Error Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
>
|
||||
Error Description Error Description Error Description Error Description
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/alert/demo/icon.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-alert ant-alert-success"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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"
|
||||
>
|
||||
Success Tips
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-info"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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"
|
||||
>
|
||||
Informational Notes
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error"
|
||||
data-show="true"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
<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
|
||||
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>
|
||||
<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
|
||||
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>
|
||||
<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
|
||||
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>
|
||||
<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
|
||||
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>
|
||||
<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/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
|
||||
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
|
||||
class="ant-alert ant-alert-success ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Success Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-info ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Info Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-warning ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Warning Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-no-icon"
|
||||
data-show="true"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-message"
|
||||
>
|
||||
Error Text
|
||||
</span>
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,3 +0,0 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('alert');
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
order: 6
|
||||
iframe: 250
|
||||
title:
|
||||
zh-CN: 顶部公告
|
||||
en-US: Banner
|
||||
@@ -8,11 +7,11 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
页面顶部通告形式,默认有图标且`type` 为 'warning'。
|
||||
用作顶部公告时,默认有图标,`type` 为 'warning',并有特殊样式。
|
||||
|
||||
## en-US
|
||||
|
||||
Display Alert as a banner at top of page.
|
||||
When `Alert` is used as banner, it has particular style, Icon and `type`(warning) are specified by default.
|
||||
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
@@ -22,11 +21,6 @@ ReactDOM.render(
|
||||
<Alert message="Warning text" banner />
|
||||
<br />
|
||||
<Alert message="Very long warning text warning text text text text text text text" banner closable />
|
||||
<br />
|
||||
<Alert showIcon={false} message="Warning text without icon" banner />
|
||||
<br />
|
||||
<Alert type="error" message="Error text" banner />
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
</div>
|
||||
, mountNode);
|
||||
````
|
||||
|
||||
@@ -17,13 +17,6 @@ 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>
|
||||
.ant-alert {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,26 +16,21 @@ To show close button.
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
|
||||
const onClose = (e) => {
|
||||
const onClose = function (e) {
|
||||
console.log(e, 'I was closed.');
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Alert
|
||||
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
|
||||
type="warning"
|
||||
closable
|
||||
onClose={onClose}
|
||||
/>
|
||||
<Alert
|
||||
message="Error Text"
|
||||
description="Error Description Error Description Error Description Error Description Error Description Error Description"
|
||||
type="error"
|
||||
closable
|
||||
onClose={onClose}
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
ReactDOM.render(<div>
|
||||
<Alert message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
|
||||
type="warning"
|
||||
closable
|
||||
onClose={onClose}
|
||||
/>
|
||||
<Alert message="Error Text"
|
||||
description="Error Description Error Description Error Description Error Description Error Description Error Description"
|
||||
type="error"
|
||||
closable
|
||||
onClose={onClose}
|
||||
/>
|
||||
</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
|
||||
);
|
||||
````
|
||||
@@ -16,29 +16,26 @@ Additional description for alert message.
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Alert
|
||||
message="Success Text"
|
||||
description="Success Description Success Description Success Description"
|
||||
type="success"
|
||||
/>
|
||||
<Alert
|
||||
message="Info Text"
|
||||
description="Info Description Info Description Info Description Info Description"
|
||||
type="info"
|
||||
/>
|
||||
<Alert
|
||||
message="Warning Text"
|
||||
description="Warning Description Warning Description Warning Description Warning Description"
|
||||
type="warning"
|
||||
/>
|
||||
<Alert
|
||||
message="Error Text"
|
||||
description="Error Description Error Description Error Description Error Description"
|
||||
type="error"
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
ReactDOM.render(<div>
|
||||
<Alert
|
||||
message="Success Text"
|
||||
description="Success Description Success Description Success Description"
|
||||
type="success"
|
||||
/>
|
||||
<Alert
|
||||
message="Info Text"
|
||||
description="Info Description Info Description Info Description Info Description"
|
||||
type="info"
|
||||
/>
|
||||
<Alert
|
||||
message="Warning Text"
|
||||
description="Warning Description Warning Description Warning Description Warning Description"
|
||||
type="warning"
|
||||
/>
|
||||
<Alert
|
||||
message="Error Text"
|
||||
description="Error Description Error Description Error Description Error Description"
|
||||
type="error"
|
||||
/>
|
||||
</div>, mountNode);
|
||||
````
|
||||
|
||||
@@ -16,37 +16,34 @@ Decent icon make information more clear and more friendly.
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Alert message="Success Tips" type="success" showIcon />
|
||||
<Alert message="Informational Notes" type="info" showIcon />
|
||||
<Alert message="Warning" type="warning" showIcon />
|
||||
<Alert message="Error" type="error" showIcon />
|
||||
<Alert
|
||||
message="Success Tips"
|
||||
description="Detailed description and advices about successful copywriting."
|
||||
type="success"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
message="Informational Notes"
|
||||
description="Additional description and informations about copywriting."
|
||||
type="info"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
message="Warning"
|
||||
description="This is a warning notice about copywriting."
|
||||
type="warning"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
message="Error"
|
||||
description="This is an error message about copywriting."
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
ReactDOM.render(<div>
|
||||
<Alert message="Success Tips" type="success" showIcon />
|
||||
<Alert message="Informational Notes" type="info" showIcon />
|
||||
<Alert message="Warning" type="warning" showIcon />
|
||||
<Alert message="Error" type="error" showIcon />
|
||||
<Alert
|
||||
message="success tips"
|
||||
description="Detailed description and advices about successful copywriting."
|
||||
type="success"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
message="Informational Notes"
|
||||
description="Additional description and informations about copywriting."
|
||||
type="info"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
message="Warning"
|
||||
description="This is a warning notice about copywriting."
|
||||
type="warning"
|
||||
showIcon
|
||||
/>
|
||||
<Alert
|
||||
message="Error"
|
||||
description="This is an error message about copywriting."
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
</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
|
||||
);
|
||||
````
|
||||
@@ -16,13 +16,10 @@ There are 4 types of Alert: `success`, `info`, `warning`, `error`.
|
||||
````jsx
|
||||
import { Alert } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Alert message="Success Text" type="success" />
|
||||
<Alert message="Info Text" type="info" />
|
||||
<Alert message="Warning Text" type="warning" />
|
||||
<Alert message="Error Text" type="error" />
|
||||
</div>,
|
||||
mountNode
|
||||
);
|
||||
ReactDOM.render(<div>
|
||||
<Alert message="Success Text" type="success" />
|
||||
<Alert message="Info Text" type="info" />
|
||||
<Alert message="Warning Text" type="warning" />
|
||||
<Alert message="Error Text" type="error" />
|
||||
</div>, mountNode);
|
||||
````
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
category: Components
|
||||
type: Feedback
|
||||
type: Views
|
||||
title: Alert
|
||||
---
|
||||
|
||||
@@ -8,20 +8,18 @@ Alert component for feedback.
|
||||
|
||||
## When To Use
|
||||
|
||||
- When you need to show alert messages to users.
|
||||
- When you need a persistent static container which is closable by user actions.
|
||||
- When you need to show alert messages for users.
|
||||
- When you need a persist static container, and closable by user actions.
|
||||
|
||||
## API
|
||||
|
||||
| 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 | - |
|
||||
| Property | Description | Type | Default |
|
||||
|----------- |--------------------------------------------------------- | ---------- |-------|
|
||||
| type | Type of Alert styles, options:`success`, `info`, `warning`, `error` | String | `info` |
|
||||
| closable | Whether Alert can be closed | Boolean | - |
|
||||
| closeText | Close text to show | React.Node | - |
|
||||
| message | Content of Alert | React.Node | - |
|
||||
| description | Additional content of Alert | React.Node | - |
|
||||
| onClose | Callback when close Alert | Function | - |
|
||||
| showIcon | Whether to show icon | Boolean | false |
|
||||
| banner | Whether to show as banner | Boolean | false |
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
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 getDataOrAriaProps from '../_util/getDataOrAriaProps';
|
||||
|
||||
function noop() {}
|
||||
|
||||
@@ -21,33 +20,29 @@ export interface AlertProps {
|
||||
/** Additional content of Alert */
|
||||
description?: React.ReactNode;
|
||||
/** Callback when close Alert */
|
||||
onClose?: React.MouseEventHandler<HTMLAnchorElement>;
|
||||
/** Trigger when animation ending of Alert */
|
||||
afterClose?: () => void;
|
||||
onClose?: React.MouseEventHandler<any>;
|
||||
/** 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> {
|
||||
static defaultProps = {
|
||||
type: 'info',
|
||||
};
|
||||
|
||||
handleClose = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
closing: true,
|
||||
closed: false,
|
||||
};
|
||||
}
|
||||
handleClose = (e) => {
|
||||
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
|
||||
@@ -57,99 +52,62 @@ 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)();
|
||||
};
|
||||
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
description,
|
||||
prefixCls = 'ant-alert',
|
||||
message,
|
||||
closeText,
|
||||
banner,
|
||||
className = '',
|
||||
style,
|
||||
icon,
|
||||
let {
|
||||
closable, description, type, prefixCls = 'ant-alert', message, closeText, showIcon, banner,
|
||||
className = '', style,
|
||||
} = this.props;
|
||||
let { closable, type, showIcon, iconType } = this.props;
|
||||
|
||||
// banner模式默认有 Icon
|
||||
showIcon = banner && showIcon === undefined ? true : showIcon;
|
||||
showIcon = showIcon || banner;
|
||||
// banner模式默认为警告
|
||||
type = banner && type === undefined ? 'warning' : type || 'info';
|
||||
type = banner ? 'warning' : type;
|
||||
|
||||
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]: true,
|
||||
[`${prefixCls}-${type}`]: true,
|
||||
[`${prefixCls}-close`]: !this.state.closing,
|
||||
[`${prefixCls}-with-description`]: !!description,
|
||||
[`${prefixCls}-no-icon`]: !showIcon,
|
||||
[`${prefixCls}-banner`]: !!banner,
|
||||
[className]: !!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" />}
|
||||
</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=""
|
||||
@@ -157,11 +115,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}
|
||||
{closable ? <a onClick={this.handleClose} className={`${prefixCls}-close-icon`}>
|
||||
{closeText || <Icon type="cross" />}
|
||||
</a> : null}
|
||||
</div>
|
||||
</Animate>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 警告提示
|
||||
type: 反馈
|
||||
type: Views
|
||||
title: Alert
|
||||
---
|
||||
|
||||
@@ -14,15 +14,14 @@ title: Alert
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| 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 | 无 |
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|----------- |--------------------------------------------------------- | ---------- |-------|
|
||||
| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | String | `info` |
|
||||
| closable | 默认不显示关闭按钮 | Boolean | 无 |
|
||||
| closeText | 自定义关闭按钮 | React.Node | 无 |
|
||||
| message | 警告提示内容 | React.Node | 无 |
|
||||
| description | 警告提示的辅助性文字介绍 | React.Node | 无 |
|
||||
| onClose | 关闭时触发的回调函数 | Function | 无 |
|
||||
| showIcon | 是否显示辅助图标 | Boolean | false |
|
||||
| banner | 是否用作顶部公告 | Boolean | false |
|
||||
|
||||
|
||||
@@ -1,85 +1,80 @@
|
||||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
@import "../../style/themes/default";
|
||||
|
||||
@alert-prefix-cls: ~'@{ant-prefix}-alert';
|
||||
|
||||
@alert-message-color: @heading-color;
|
||||
@alert-text-color: @text-color;
|
||||
@alert-close-color: @text-color-secondary;
|
||||
@alert-close-hover-color: #404040;
|
||||
@alert-prefix-cls: ~"@{ant-prefix}-alert";
|
||||
|
||||
.@{alert-prefix-cls} {
|
||||
.reset-component;
|
||||
position: relative;
|
||||
padding: 8px 15px 8px 37px;
|
||||
padding: 8px 48px 8px 38px;
|
||||
border-radius: @border-radius-base;
|
||||
color: @text-color;
|
||||
font-size: @font-size-base;
|
||||
line-height: 16px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&&-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: 14px;
|
||||
top: 9px;
|
||||
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: 1px solid tint(@success-color, 80%);
|
||||
background-color: tint(@success-color, 90%);
|
||||
.@{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: 1px solid tint(@primary-color, 80%);
|
||||
background-color: tint(@primary-color, 90%);
|
||||
.@{alert-prefix-cls}-icon {
|
||||
color: @alert-info-icon-color;
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-warning {
|
||||
border: @border-width-base @border-style-base @alert-warning-border-color;
|
||||
background-color: @alert-warning-bg-color;
|
||||
border: 1px solid tint(@warning-color, 80%);
|
||||
background-color: tint(@warning-color, 90%);
|
||||
.@{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: 1px solid tint(@error-color, 80%);
|
||||
background-color: tint(@error-color, 90%);
|
||||
.@{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: @legend-color;
|
||||
transition: color .3s ease;
|
||||
&:hover {
|
||||
color: @alert-close-hover-color;
|
||||
color: #404040;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,21 +85,22 @@
|
||||
}
|
||||
|
||||
&-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;
|
||||
margin-bottom: 10px;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -117,8 +113,8 @@
|
||||
}
|
||||
|
||||
&-with-description &-message {
|
||||
font-size: @font-size-lg;
|
||||
color: @alert-message-color;
|
||||
font-size: 14px;
|
||||
color: @heading-color;
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
@@ -132,12 +128,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,304 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import Affix from '../affix';
|
||||
import AnchorLink from './AnchorLink';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import raf from 'raf';
|
||||
|
||||
function getDefaultContainer() {
|
||||
return window;
|
||||
}
|
||||
|
||||
function getOffsetTop(element: HTMLElement, container: AnchorContainer): number {
|
||||
if (!element) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!element.getClientRects().length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return rect.top;
|
||||
}
|
||||
|
||||
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 -= 2) * t * t + 2) + b;
|
||||
}
|
||||
|
||||
const sharpMatcherRegx = /#([^#]+)$/;
|
||||
function scrollTo(
|
||||
href: string,
|
||||
offsetTop = 0,
|
||||
getContainer: () => AnchorContainer,
|
||||
callback = () => {},
|
||||
) {
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(href);
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
const targetElement = document.getElementById(sharpLinkMatch[1]);
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
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;
|
||||
}
|
||||
if (time < 450) {
|
||||
raf(frameFunc);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
raf(frameFunc);
|
||||
}
|
||||
|
||||
type Section = {
|
||||
link: string;
|
||||
top: number;
|
||||
};
|
||||
|
||||
export type AnchorContainer = HTMLElement | Window;
|
||||
|
||||
export interface AnchorProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
offsetTop?: number;
|
||||
bounds?: number;
|
||||
affix?: boolean;
|
||||
showInkInFixed?: boolean;
|
||||
getContainer?: () => AnchorContainer;
|
||||
onClick?: (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: { title: React.ReactNode; href: string },
|
||||
) => void;
|
||||
}
|
||||
|
||||
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> {
|
||||
static Link: typeof AnchorLink;
|
||||
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-anchor',
|
||||
affix: true,
|
||||
showInkInFixed: false,
|
||||
getContainer: getDefaultContainer,
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
antAnchor: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {
|
||||
activeLink: null,
|
||||
};
|
||||
|
||||
private inkNode: HTMLSpanElement;
|
||||
|
||||
private links: string[] = [];
|
||||
private scrollEvent: any;
|
||||
private animating: boolean;
|
||||
|
||||
getChildContext() {
|
||||
const antAnchor: 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,
|
||||
onClick: this.props.onClick,
|
||||
};
|
||||
return { antAnchor };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { getContainer } = this.props as AnchorDefaultProps;
|
||||
this.scrollEvent = addEventListener(getContainer(), 'scroll', this.handleScroll);
|
||||
this.handleScroll();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.scrollEvent) {
|
||||
this.scrollEvent.remove();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.updateInk();
|
||||
}
|
||||
|
||||
handleScroll = () => {
|
||||
if (this.animating) {
|
||||
return;
|
||||
}
|
||||
const { offsetTop, bounds } = this.props;
|
||||
this.setState({
|
||||
activeLink: this.getCurrentAnchor(offsetTop, bounds),
|
||||
});
|
||||
};
|
||||
|
||||
handleScrollTo = (link: string) => {
|
||||
const { offsetTop, getContainer } = this.props as AnchorDefaultProps;
|
||||
this.animating = true;
|
||||
this.setState({ activeLink: link });
|
||||
scrollTo(link, offsetTop, getContainer, () => {
|
||||
this.animating = false;
|
||||
});
|
||||
};
|
||||
|
||||
getCurrentAnchor(offsetTop = 0, bounds = 5): string {
|
||||
const activeLink = '';
|
||||
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;
|
||||
}
|
||||
const target = document.getElementById(sharpLinkMatch[1]);
|
||||
if (target) {
|
||||
const top = getOffsetTop(target, container);
|
||||
if (top < offsetTop + bounds) {
|
||||
linkSections.push({
|
||||
link,
|
||||
top,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (linkSections.length) {
|
||||
const maxSection = linkSections.reduce((prev, curr) => (curr.top > prev.top ? curr : prev));
|
||||
return maxSection.link;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
updateInk = () => {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const { prefixCls } = this.props;
|
||||
const anchorNode = ReactDOM.findDOMNode(this) as Element;
|
||||
const linkNode = anchorNode.getElementsByClassName(`${prefixCls}-link-title-active`)[0];
|
||||
if (linkNode) {
|
||||
this.inkNode.style.top = `${(linkNode as any).offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
|
||||
}
|
||||
};
|
||||
|
||||
saveInkNode = (node: HTMLSpanElement) => {
|
||||
this.inkNode = node;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
prefixCls,
|
||||
className = '',
|
||||
style,
|
||||
offsetTop,
|
||||
affix,
|
||||
showInkInFixed,
|
||||
children,
|
||||
getContainer,
|
||||
} = this.props;
|
||||
const { activeLink } = this.state;
|
||||
|
||||
const inkClass = classNames(`${prefixCls}-ink-ball`, {
|
||||
visible: activeLink,
|
||||
});
|
||||
|
||||
const wrapperClass = classNames(className, `${prefixCls}-wrapper`);
|
||||
|
||||
const anchorClass = classNames(prefixCls, {
|
||||
fixed: !affix && !showInkInFixed,
|
||||
});
|
||||
|
||||
const wrapperStyle = {
|
||||
maxHeight: offsetTop ? `calc(100vh - ${offsetTop}px)` : '100vh',
|
||||
...style,
|
||||
};
|
||||
|
||||
const anchorContent = (
|
||||
<div className={wrapperClass} style={wrapperStyle}>
|
||||
<div className={anchorClass}>
|
||||
<div className={`${prefixCls}-ink`}>
|
||||
<span className={inkClass} ref={this.saveInkNode} />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return !affix ? (
|
||||
anchorContent
|
||||
) : (
|
||||
<Affix offsetTop={offsetTop} target={getContainer}>
|
||||
{anchorContent}
|
||||
</Affix>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { AntAnchor } from './Anchor';
|
||||
|
||||
export interface AnchorLinkProps {
|
||||
prefixCls?: string;
|
||||
href: string;
|
||||
title: React.ReactNode;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-anchor',
|
||||
href: '#',
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
antAnchor: PropTypes.object,
|
||||
};
|
||||
|
||||
context: {
|
||||
antAnchor: AntAnchor;
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.context.antAnchor.registerLink(this.props.href);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: AnchorLinkProps) {
|
||||
const { href } = nextProps;
|
||||
if (this.props.href !== href) {
|
||||
this.context.antAnchor.unregisterLink(this.props.href);
|
||||
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);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { prefixCls, href, title, children } = this.props;
|
||||
const active = this.context.antAnchor.activeLink === href;
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<a
|
||||
className={titleClassName}
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Anchor from '..';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
describe('Anchor Render', () => {
|
||||
it('Anchor render perfectly', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find('a[href="#API"]').simulate('click');
|
||||
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - click', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find('a[href="http://www.example.com/#API"]').simulate('click');
|
||||
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scroll', () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="API">Hello</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="API">Hello</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="##API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.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 });
|
||||
});
|
||||
});
|
||||
@@ -1,229 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<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-fixed"
|
||||
title="Fixed demo"
|
||||
>
|
||||
Fixed 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>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onClick.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-fixed"
|
||||
title="Fixed demo"
|
||||
>
|
||||
Fixed 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-fixed"
|
||||
title="Fixed demo"
|
||||
>
|
||||
Fixed 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>
|
||||
`;
|
||||
@@ -1,3 +0,0 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('anchor');
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
order: 0
|
||||
title:
|
||||
zh-CN: 基本
|
||||
en-US: Basic
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
最简单的用法。
|
||||
|
||||
## en-US
|
||||
|
||||
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-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
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-affix {
|
||||
z-index: 11;
|
||||
}
|
||||
</style>
|
||||
@@ -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-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
|
||||
);
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
zh-CN: 静态位置
|
||||
en-US: Static Anchor
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
不浮动,状态不随页面滚动变化。
|
||||
|
||||
## en-US
|
||||
|
||||
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-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
|
||||
);
|
||||
```
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
category: Components
|
||||
type: Other
|
||||
cols: 2
|
||||
title: Anchor
|
||||
---
|
||||
|
||||
Hyperlinks to scroll on one page.
|
||||
|
||||
## When To Use
|
||||
|
||||
For displaying anchor hyperlinks on page and jumping between them.
|
||||
|
||||
## API
|
||||
|
||||
### Anchor Props
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| affix | Fixed mode of Anchor | boolean | true |
|
||||
| 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
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| href | target of hyperlink | string | |
|
||||
| title | content of hyperlink | string\|ReactNode | |
|
||||
@@ -1,8 +0,0 @@
|
||||
import Anchor from './Anchor';
|
||||
import AnchorLink from './AnchorLink';
|
||||
|
||||
export { AnchorProps } from './Anchor';
|
||||
export { AnchorLinkProps } from './AnchorLink';
|
||||
|
||||
Anchor.Link = AnchorLink;
|
||||
export default Anchor;
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 锚点
|
||||
cols: 2
|
||||
type: 其他
|
||||
title: Anchor
|
||||
---
|
||||
|
||||
用于跳转到页面指定位置。
|
||||
|
||||
## 何时使用
|
||||
|
||||
需要展现当前页面上可供跳转的锚点链接,以及快速在锚点之间跳转。
|
||||
|
||||
## API
|
||||
|
||||
### Anchor Props
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| affix | 固定模式 | boolean | true |
|
||||
| bounds | 锚点区域边界 | number | 5(px) |
|
||||
| getContainer | 指定滚动的容器 | () => HTMLElement | () => window |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | number | |
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | |
|
||||
| showInkInFixed | 固定模式是否显示小圆点 | boolean | false |
|
||||
| onClick | `click` 事件的 handler | Function(e: Event, link: Object) | - |
|
||||
|
||||
### Link Props
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| href | 锚点链接 | string | |
|
||||
| title | 文字内容 | string\|ReactNode | |
|
||||
@@ -1,81 +0,0 @@
|
||||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@anchor-border-width: 2px;
|
||||
|
||||
.@{ant-prefix}-anchor {
|
||||
.reset-component;
|
||||
position: relative;
|
||||
padding-left: @anchor-border-width;
|
||||
|
||||
&-wrapper {
|
||||
background-color: @component-background;
|
||||
overflow: auto;
|
||||
padding-left: 4px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
&-ink {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
&:before {
|
||||
content: ' ';
|
||||
position: relative;
|
||||
width: @anchor-border-width;
|
||||
height: 100%;
|
||||
display: block;
|
||||
background-color: @border-color-split;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&-ball {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
border: 2px solid @primary-color;
|
||||
background-color: @component-background;
|
||||
left: 50%;
|
||||
transition: top 0.3s ease-in-out;
|
||||
transform: translateX(-50%);
|
||||
&.visible {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed &-ink &-ink-ball {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-link {
|
||||
padding: 7px 0 7px 16px;
|
||||
line-height: 1.143;
|
||||
|
||||
&-title {
|
||||
display: block;
|
||||
position: relative;
|
||||
transition: all 0.3s;
|
||||
color: @text-color;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 6px;
|
||||
|
||||
&:only-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-active > &-title {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-link &-link {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
||||
@@ -1,36 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
|
||||
export interface InputElementProps {
|
||||
children: React.ReactElement<any>;
|
||||
}
|
||||
|
||||
export default class InputElement extends React.Component<InputElementProps, any> {
|
||||
private ele: HTMLInputElement;
|
||||
|
||||
focus = () => {
|
||||
this.ele.focus
|
||||
? this.ele.focus()
|
||||
: (ReactDOM.findDOMNode(this.ele) as HTMLInputElement).focus();
|
||||
};
|
||||
blur = () => {
|
||||
this.ele.blur ? this.ele.blur() : (ReactDOM.findDOMNode(this.ele) as HTMLInputElement).blur();
|
||||
};
|
||||
saveRef = (ele: HTMLInputElement) => {
|
||||
this.ele = ele;
|
||||
const { ref: childRef } = this.props.children as any;
|
||||
if (typeof childRef === 'function') {
|
||||
childRef(ele);
|
||||
}
|
||||
};
|
||||
render() {
|
||||
return React.cloneElement(
|
||||
this.props.children,
|
||||
{
|
||||
...this.props,
|
||||
ref: this.saveRef,
|
||||
},
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,491 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
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"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-select-search__field"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1`] = `
|
||||
<div
|
||||
class="certain-category-search-wrapper"
|
||||
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%"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<span
|
||||
class="ant-select-search__field ant-input-affix-wrapper"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<i
|
||||
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
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<textarea
|
||||
class="ant-input custom ant-select-search__field"
|
||||
placeholder="input here"
|
||||
style="height:50px"
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
try to type \`b\`
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-select-search__field"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-select-search__field"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly 1`] = `
|
||||
<div
|
||||
class="global-search-wrapper"
|
||||
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%"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<span
|
||||
class="ant-select-search__field ant-input-affix-wrapper"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<button
|
||||
class="ant-btn search-btn ant-btn-primary ant-btn-lg"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<i
|
||||
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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,3 +0,0 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('auto-complete');
|
||||
@@ -1,38 +0,0 @@
|
||||
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>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('textarea').length).toBe(1);
|
||||
wrapper.find('textarea').simulate('change', { target: { value: '123' } });
|
||||
const dropdownWrapper = mount(
|
||||
wrapper
|
||||
.find('Trigger')
|
||||
.instance()
|
||||
.getComponent(),
|
||||
);
|
||||
|
||||
// should not filter data source defaultly
|
||||
expect(dropdownWrapper.find('MenuItem').length).toBe(3);
|
||||
});
|
||||
|
||||
it('child.ref should work', () => {
|
||||
const mockRef = jest.fn();
|
||||
mount(
|
||||
<AutoComplete dataSource={[]}>
|
||||
<input ref={mockRef} />
|
||||
</AutoComplete>,
|
||||
);
|
||||
expect(mockRef).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -20,12 +20,13 @@ function onSelect(value) {
|
||||
console.log('onSelect', value);
|
||||
}
|
||||
|
||||
class Complete extends React.Component {
|
||||
state = {
|
||||
dataSource: [],
|
||||
}
|
||||
|
||||
handleSearch = (value) => {
|
||||
const Complete = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
dataSource: [],
|
||||
};
|
||||
},
|
||||
handleChange(value) {
|
||||
this.setState({
|
||||
dataSource: !value ? [] : [
|
||||
value,
|
||||
@@ -33,8 +34,7 @@ class Complete extends React.Component {
|
||||
value + value + value,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
render() {
|
||||
const { dataSource } = this.state;
|
||||
return (
|
||||
@@ -42,12 +42,11 @@ class Complete extends React.Component {
|
||||
dataSource={dataSource}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={this.handleSearch}
|
||||
placeholder="input here"
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
ReactDOM.render(<Complete />, mountNode);
|
||||
````
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 查询模式 - 确定类目
|
||||
en-US: Lookup-Patterns - Certain Category
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
[查询模式: 确定类目](https://ant.design/docs/spec/reaction#Lookup-Patterns) 示例。
|
||||
|
||||
## en-US
|
||||
|
||||
Demonstration of [Lookup Patterns: Certain Category](https://ant.design/docs/spec/reaction#Lookup-Patterns).
|
||||
Basic Usage, set datasource of autocomplete with `dataSource` property.
|
||||
|
||||
````jsx
|
||||
import { Icon, Input, AutoComplete } from 'antd';
|
||||
|
||||
const Option = AutoComplete.Option;
|
||||
const OptGroup = AutoComplete.OptGroup;
|
||||
|
||||
const dataSource = [{
|
||||
title: '话题',
|
||||
children: [{
|
||||
title: 'AntDesign',
|
||||
count: 10000,
|
||||
}, {
|
||||
title: 'AntDesign UI',
|
||||
count: 10600,
|
||||
}],
|
||||
}, {
|
||||
title: '问题',
|
||||
children: [{
|
||||
title: 'AntDesign UI 有多好',
|
||||
count: 60100,
|
||||
}, {
|
||||
title: 'AntDesign 是啥',
|
||||
count: 30010,
|
||||
}],
|
||||
}, {
|
||||
title: '文章',
|
||||
children: [{
|
||||
title: 'AntDesign 是一个设计语言',
|
||||
count: 100000,
|
||||
}],
|
||||
}];
|
||||
|
||||
function renderTitle(title) {
|
||||
return (
|
||||
<span>
|
||||
{title}
|
||||
<a
|
||||
style={{ float: 'right' }}
|
||||
href="https://www.google.com/search?q=antd"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>更多
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const options = dataSource.map(group => (
|
||||
<OptGroup
|
||||
key={group.title}
|
||||
label={renderTitle(group.title)}
|
||||
>
|
||||
{group.children.map(opt => (
|
||||
<Option key={opt.title} value={opt.title}>
|
||||
{opt.title}
|
||||
<span className="certain-search-item-count">{opt.count} 人 关注</span>
|
||||
</Option>
|
||||
))}
|
||||
</OptGroup>
|
||||
)).concat([
|
||||
<Option disabled key="all" className="show-all">
|
||||
<a
|
||||
href="https://www.google.com/search?q=antd"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
查看所有结果
|
||||
</a>
|
||||
</Option>,
|
||||
]);
|
||||
|
||||
function Complete() {
|
||||
return (
|
||||
<div className="certain-category-search-wrapper" style={{ width: 250 }}>
|
||||
<AutoComplete
|
||||
className="certain-category-search"
|
||||
dropdownClassName="certain-category-search-dropdown"
|
||||
dropdownMatchSelectWidth={false}
|
||||
dropdownStyle={{ width: 300 }}
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
dataSource={options}
|
||||
placeholder="input here"
|
||||
optionLabelProp="value"
|
||||
>
|
||||
<Input suffix={<Icon type="search" className="certain-category-icon" />} />
|
||||
</AutoComplete>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<Complete />, mountNode);
|
||||
````
|
||||
|
||||
````css
|
||||
.certain-category-search.ant-select-auto-complete .ant-input-affix-wrapper .ant-input-suffix {
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.certain-category-search-dropdown .ant-select-dropdown-menu-item-group-title {
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.certain-category-search-dropdown .ant-select-dropdown-menu-item-group {
|
||||
border-bottom: 1px solid #F6F6F6;
|
||||
}
|
||||
|
||||
.certain-category-search-dropdown .ant-select-dropdown-menu-item {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.certain-category-search-dropdown .ant-select-dropdown-menu-item.show-all {
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.certain-category-search-dropdown .ant-select-dropdown-menu {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.certain-search-item-count {
|
||||
position: absolute;
|
||||
color: #999;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.certain-category-search.ant-select-focused .certain-category-icon {
|
||||
color: #108ee9;
|
||||
}
|
||||
|
||||
.certain-category-icon {
|
||||
color: #6E6E6E;
|
||||
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
font-size: 16px;
|
||||
}
|
||||
````
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 自定义输入组件
|
||||
en-US: Customize Input Component
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
自定义输入组件。
|
||||
|
||||
## en-US
|
||||
|
||||
Customize Input Component
|
||||
|
||||
````jsx
|
||||
import { AutoComplete, Input } from 'antd';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
function onSelect(value) {
|
||||
console.log('onSelect', value);
|
||||
}
|
||||
|
||||
class Complete extends React.Component {
|
||||
state = {
|
||||
dataSource: [],
|
||||
}
|
||||
|
||||
handleSearch = (value) => {
|
||||
this.setState({
|
||||
dataSource: !value ? [] : [
|
||||
value,
|
||||
value + value,
|
||||
value + value + value,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
handleKeyPress = (ev) => {
|
||||
console.log('handleKeyPress', ev);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dataSource } = this.state;
|
||||
return (
|
||||
<AutoComplete
|
||||
dataSource={dataSource}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={this.handleSearch}
|
||||
>
|
||||
<TextArea
|
||||
placeholder="input here"
|
||||
className="custom"
|
||||
style={{ height: 50 }}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
/>
|
||||
</AutoComplete>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Complete />, mountNode);
|
||||
````
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 不区分大小写
|
||||
en-US: Non-case-sensitive AutoComplete
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
不区分大小写的 AutoComplete
|
||||
|
||||
## en-US
|
||||
|
||||
A non-case-sensitive AutoComplete
|
||||
|
||||
````jsx
|
||||
import { AutoComplete } from 'antd';
|
||||
|
||||
const dataSource = ['Burns Bay Road', 'Downing Street', 'Wall Street'];
|
||||
|
||||
function Complete() {
|
||||
return (
|
||||
<AutoComplete
|
||||
style={{ width: 200 }}
|
||||
dataSource={dataSource}
|
||||
placeholder="try to type `b`"
|
||||
filterOption={(inputValue, option) => option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<Complete />, mountNode);
|
||||
````
|
||||
@@ -18,12 +18,13 @@ import { AutoComplete } from 'antd';
|
||||
|
||||
const Option = AutoComplete.Option;
|
||||
|
||||
class Complete extends React.Component {
|
||||
state = {
|
||||
result: [],
|
||||
}
|
||||
|
||||
handleSearch = (value) => {
|
||||
const Complete = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
result: [],
|
||||
};
|
||||
},
|
||||
handleChange(value) {
|
||||
let result;
|
||||
if (!value || value.indexOf('@') >= 0) {
|
||||
result = [];
|
||||
@@ -31,22 +32,22 @@ class Complete extends React.Component {
|
||||
result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
|
||||
}
|
||||
this.setState({ result });
|
||||
}
|
||||
|
||||
},
|
||||
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 }}
|
||||
onSearch={this.handleSearch}
|
||||
placeholder="input here"
|
||||
onChange={this.handleChange}
|
||||
>
|
||||
{children}
|
||||
</AutoComplete>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
ReactDOM.render(<Complete />, mountNode);
|
||||
````
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
---
|
||||
order: 5
|
||||
title:
|
||||
zh-CN: 查询模式 - 不确定类目
|
||||
en-US: Lookup-Patterns - Uncertain Category
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
[查询模式: 不确定类目](https://ant.design/docs/spec/reaction#Lookup-Patterns) 示例。
|
||||
|
||||
## en-US
|
||||
|
||||
Demonstration of [Lookup Patterns: Uncertain Category](https://ant.design/docs/spec/reaction#Lookup-Patterns).
|
||||
Basic Usage, set datasource of autocomplete with `dataSource` property.
|
||||
|
||||
````jsx
|
||||
import {
|
||||
Icon, Button, Input, AutoComplete,
|
||||
} from 'antd';
|
||||
|
||||
const Option = AutoComplete.Option;
|
||||
|
||||
function onSelect(value) {
|
||||
console.log('onSelect', value);
|
||||
}
|
||||
|
||||
function getRandomInt(max, min = 0) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min; // eslint-disable-line no-mixed-operators
|
||||
}
|
||||
|
||||
function searchResult(query) {
|
||||
return (new Array(getRandomInt(5))).join('.').split('.')
|
||||
.map((item, idx) => ({
|
||||
query,
|
||||
category: `${query}${idx}`,
|
||||
count: getRandomInt(200, 100),
|
||||
}));
|
||||
}
|
||||
|
||||
function renderOption(item) {
|
||||
return (
|
||||
<Option key={item.category} text={item.category}>
|
||||
{item.query} 在
|
||||
<a
|
||||
href={`https://s.taobao.com/search?q=${item.query}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{item.category}
|
||||
</a>
|
||||
区块中
|
||||
<span className="global-search-item-count">约 {item.count} 个结果</span>
|
||||
</Option>
|
||||
);
|
||||
}
|
||||
|
||||
class Complete extends React.Component {
|
||||
state = {
|
||||
dataSource: [],
|
||||
}
|
||||
|
||||
handleSearch = (value) => {
|
||||
this.setState({
|
||||
dataSource: value ? searchResult(value) : [],
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dataSource } = this.state;
|
||||
return (
|
||||
<div className="global-search-wrapper" style={{ width: 300 }}>
|
||||
<AutoComplete
|
||||
className="global-search"
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
dataSource={dataSource.map(renderOption)}
|
||||
onSelect={onSelect}
|
||||
onSearch={this.handleSearch}
|
||||
placeholder="input here"
|
||||
optionLabelProp="text"
|
||||
>
|
||||
<Input
|
||||
suffix={(
|
||||
<Button className="search-btn" size="large" type="primary">
|
||||
<Icon type="search" />
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
</AutoComplete>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Complete />, mountNode);
|
||||
````
|
||||
|
||||
````css
|
||||
.global-search-wrapper {
|
||||
padding-right: 50px;
|
||||
}
|
||||
|
||||
.global-search {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.global-search.ant-select-auto-complete .ant-select-selection--single {
|
||||
margin-right: -46px;
|
||||
}
|
||||
|
||||
.global-search.ant-select-auto-complete .ant-input-affix-wrapper .ant-input:not(:last-child) {
|
||||
padding-right: 62px;
|
||||
}
|
||||
|
||||
.global-search.ant-select-auto-complete .ant-input-affix-wrapper .ant-input-suffix {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.global-search.ant-select-auto-complete .ant-input-affix-wrapper .ant-input-suffix button {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.global-search-item-count {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
}
|
||||
````
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
type: Data Entry
|
||||
cols: 2
|
||||
type: Form Controls
|
||||
cols: 1
|
||||
title: AutoComplete
|
||||
---
|
||||
|
||||
@@ -9,7 +9,7 @@ Autocomplete function of input field.
|
||||
|
||||
## When To Use
|
||||
|
||||
When there is a need for autocomplete functionality.
|
||||
When need to use autocomplete function.
|
||||
|
||||
## API
|
||||
|
||||
@@ -18,33 +18,13 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
<AutoComplete dataSource={dataSource} />
|
||||
```
|
||||
|
||||
| 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\[]\| - |
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|----------------|----------------------------------|------------|--------|
|
||||
| dataSource | Data source for autocomplete | Array | |
|
||||
| value | selected option | String/Array<String>/{key: String, label: React.Node}/Array<{key, label}> | - |
|
||||
| defaultValue | Initial selected option. | string/Array<String> | - |
|
||||
| allowClear | Show clear button, effective in multiple mode only. | boolean | false |
|
||||
| onChange | Called when select an option or input value change, or value of input is changed | function(value, label) | - |
|
||||
| onSelect | Called when a option is selected. param is option's value and option instance. | function(value, option) | - |
|
||||
| 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() | - |
|
||||
| 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,53 +1,34 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import Select, { OptionProps, OptGroupProps } from '../select';
|
||||
import { Option, OptGroup } from 'rc-select';
|
||||
import classNames from 'classnames';
|
||||
import Select, { AbstractSelectProps, SelectValue, OptionProps, OptGroupProps } from '../select';
|
||||
import Input, { InputProps } 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 AutoCompleteInputProps {
|
||||
onChange?: React.FormEventHandler<any>;
|
||||
value: any;
|
||||
export interface SelectedValue {
|
||||
key: string;
|
||||
label: React.ReactNode;
|
||||
}
|
||||
|
||||
export type ValidInputElement =
|
||||
| HTMLInputElement
|
||||
| HTMLTextAreaElement
|
||||
| React.ReactElement<AutoCompleteInputProps>;
|
||||
export interface DataSourceItemObject { value: string; text: string; };
|
||||
export type DataSourceItemType = string | DataSourceItemObject;
|
||||
|
||||
export interface AutoCompleteProps extends AbstractSelectProps {
|
||||
value?: SelectValue;
|
||||
defaultValue?: SelectValue;
|
||||
dataSource?: DataSourceItemType[];
|
||||
autoFocus?: boolean;
|
||||
backfill?: boolean;
|
||||
export interface AutoCompleteProps {
|
||||
size?: 'large' | 'small' | 'default';
|
||||
className?: string;
|
||||
notFoundContent?: Element;
|
||||
dataSource: DataSourceItemType[];
|
||||
prefixCls?: string;
|
||||
transitionName?: string;
|
||||
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>>;
|
||||
choiceTransitionName?: string;
|
||||
showSearch?: boolean;
|
||||
defaultValue?: string | Array<any> | SelectedValue | Array<SelectedValue>;
|
||||
value?: string | Array<any> | SelectedValue | Array<SelectedValue>;
|
||||
allowClear?: boolean;
|
||||
onChange?: (value: string | Array<any> | SelectedValue | Array<SelectedValue>) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
@@ -57,46 +38,15 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
|
||||
optionLabelProp: 'children',
|
||||
choiceTransitionName: 'zoom',
|
||||
showSearch: false,
|
||||
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.props };
|
||||
// https://github.com/ant-design/ant-design/pull/7742
|
||||
delete elementProps.children;
|
||||
return <InputElement {...elementProps}>{element}</InputElement>;
|
||||
};
|
||||
|
||||
focus() {
|
||||
this.select.focus();
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.select.blur();
|
||||
}
|
||||
|
||||
saveSelect = (node: any) => {
|
||||
this.select = node;
|
||||
static contextTypes = {
|
||||
antLocale: React.PropTypes.object,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
size,
|
||||
className = '',
|
||||
notFoundContent,
|
||||
prefixCls,
|
||||
optionLabelProp,
|
||||
dataSource,
|
||||
children,
|
||||
let {
|
||||
size, className = '', notFoundContent, prefixCls, optionLabelProp, dataSource, children,
|
||||
} = this.props;
|
||||
|
||||
const cls = classNames({
|
||||
@@ -104,47 +54,29 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
[className]: !!className,
|
||||
[`${prefixCls}-show-search`]: true,
|
||||
[`${prefixCls}-auto-complete`]: true,
|
||||
});
|
||||
|
||||
let options;
|
||||
const childArray = React.Children.toArray(children);
|
||||
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[]`.',
|
||||
);
|
||||
}
|
||||
})
|
||||
: [];
|
||||
}
|
||||
const options = children || (dataSource ? dataSource.map((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}
|
||||
<Select {...this.props}
|
||||
className={cls}
|
||||
mode={Select.SECRET_COMBOBOX_MODE_DO_NOT_USE}
|
||||
optionLabelProp={optionLabelProp}
|
||||
getInputElement={this.getInputElement}
|
||||
notFoundContent={notFoundContent}
|
||||
ref={this.saveSelect}
|
||||
>
|
||||
combobox
|
||||
notFoundContent={notFoundContent} >
|
||||
{options}
|
||||
</Select>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 自动完成
|
||||
type: 数据录入
|
||||
cols: 2
|
||||
type: Form Controls
|
||||
cols: 1
|
||||
title: AutoComplete
|
||||
---
|
||||
|
||||
@@ -19,33 +19,13 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
<AutoComplete dataSource={dataSource} />
|
||||
```
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| 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\[]\| 无 |
|
||||
| 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() | - |
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|----------------|----------------------------------|------------|---------|
|
||||
| dataSource | 自动完成的数据源 | Array | |
|
||||
| value | 指定当前选中的条目 | String/Array<String>/{key: String, label: React.Node}/Array<{key, label}> | 无 |
|
||||
| defaultValue | 指定默认选中的条目 | String/Array<String>/{key: String, label: React.Node}/Array<{key, label}> | 无 |
|
||||
| allowClear | 支持清除, 单选模式有效 | boolean | false |
|
||||
| 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() | 获取焦点 |
|
||||
| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | 无 |
|
||||
| disabled | 是否禁用 | boolean | false |
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
@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';
|
||||
|
||||
.@{autocomplete-prefix-cls} {
|
||||
.reset-component;
|
||||
|
||||
&.@{select-prefix-cls} {
|
||||
.@{select-prefix-cls} {
|
||||
&-selection {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
&__rendered {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
height: 100%;
|
||||
line-height: @input-height-base;
|
||||
}
|
||||
&__placeholder {
|
||||
margin-left: (@input-padding-horizontal-base + 1px);
|
||||
margin-right: (@input-padding-horizontal-base + 1px);
|
||||
}
|
||||
|
||||
&--single {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix https://github.com/ant-design/ant-design/issues/7800
|
||||
.@{select-prefix-cls}-search--inline {
|
||||
position: static;
|
||||
float: left;
|
||||
}
|
||||
|
||||
&-allow-clear {
|
||||
.@{select-prefix-cls}-selection:hover .@{select-prefix-cls}-selection__rendered {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{input-prefix-cls} {
|
||||
background: transparent;
|
||||
border-width: @border-width-base;
|
||||
line-height: @line-height-base;
|
||||
height: @input-height-base;
|
||||
&:focus,
|
||||
&:hover {
|
||||
.hover;
|
||||
}
|
||||
&[disabled] {
|
||||
.disabled;
|
||||
}
|
||||
}
|
||||
|
||||
&-lg {
|
||||
.@{select-prefix-cls}-selection__rendered {
|
||||
line-height: @input-height-lg;
|
||||
}
|
||||
.@{input-prefix-cls} {
|
||||
padding-top: @input-padding-vertical-lg;
|
||||
padding-bottom: @input-padding-vertical-lg;
|
||||
height: @input-height-lg;
|
||||
}
|
||||
}
|
||||
|
||||
&-sm {
|
||||
.@{select-prefix-cls}-selection__rendered {
|
||||
line-height: @input-height-sm;
|
||||
}
|
||||
.@{input-prefix-cls} {
|
||||
padding-top: @input-padding-vertical-sm;
|
||||
padding-bottom: @input-padding-vertical-sm;
|
||||
height: @input-height-sm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user