Compare commits

..

No commits in common. "main" and "0.4.0" have entirely different histories.
main ... 0.4.0

4201 changed files with 111295 additions and 607603 deletions

View File

@ -1,36 +0,0 @@
const fs = require('fs');
const path = require('path');
const restCssPath = path.join(process.cwd(), 'components', 'style', 'reset.css');
const tokenStatisticPath = path.join(process.cwd(), 'components', 'version', 'token.json');
const tokenMetaPath = path.join(process.cwd(), 'components', 'version', 'token-meta.json');
function finalizeCompile() {
if (fs.existsSync(path.join(__dirname, './es'))) {
fs.copyFileSync(restCssPath, path.join(process.cwd(), 'es', 'style', 'reset.css'));
fs.copyFileSync(tokenStatisticPath, path.join(process.cwd(), 'es', 'version', 'token.json'));
fs.copyFileSync(tokenMetaPath, path.join(process.cwd(), 'es', 'version', 'token-meta.json'));
}
if (fs.existsSync(path.join(__dirname, './lib'))) {
fs.copyFileSync(restCssPath, path.join(process.cwd(), 'lib', 'style', 'reset.css'));
fs.copyFileSync(tokenStatisticPath, path.join(process.cwd(), 'lib', 'version', 'token.json'));
fs.copyFileSync(tokenMetaPath, path.join(process.cwd(), 'lib', 'version', 'token-meta.json'));
}
}
function finalizeDist() {
if (fs.existsSync(path.join(__dirname, './dist'))) {
fs.copyFileSync(restCssPath, path.join(process.cwd(), 'dist', 'reset.css'));
}
}
module.exports = {
compile: {
finalize: finalizeCompile,
},
dist: {
finalize: finalizeDist,
},
bail: true,
};

View File

@ -1,2 +0,0 @@
codecov:
branch: master

View File

@ -1,11 +1,9 @@
# 🎨 editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -1,13 +1 @@
node_modules/
**/*.spec.*
**/style/
*.html
/components/test/*
es/
lib/
_site/
dist/
site/dist/
components/version/version.ts
site/src/router/demoRoutes.js
locale/

8
.eslintrc Normal file
View File

@ -0,0 +1,8 @@
{
"parser": "babel-eslint",
"extends": ["plugin:vue-libs/recommended"], // ,"plugin:vue-libs/recommended"
"rules": {
"comma-dangle": [2, "always-multiline"],
"no-var": "error"
}
}

View File

@ -1,112 +0,0 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
jasmine: true,
jest: true,
es6: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
parser: 'babel-eslint',
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'@vue/typescript/recommended',
'@vue/prettier',
// 'prettier',
],
// extends: [
// 'eslint:recommended',
// 'plugin:vue/vue3-recommended',
// '@vue/typescript/recommended',
// '@vue/prettier',
// ],
plugins: ['markdown', 'jest', '@typescript-eslint', 'import'],
globals: {
h: true,
defineProps: 'readonly',
},
overrides: [
{
files: ['*.md'],
processor: 'markdown/markdown',
rules: {
'no-console': 'off',
},
},
{
files: ['*.ts', '*.tsx'],
// extends: ['@vue/typescript/recommended', '@vue/prettier'],
parserOptions: {
project: './tsconfig.json',
},
rules: {
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true },
],
'@typescript-eslint/ban-ts-comment': 0,
},
},
{
files: ['*.vue'],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2021,
},
rules: {
'no-console': 'off',
'vue/no-reserved-component-names': 'off',
},
},
],
rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true, argsIgnorePattern: '^_' },
],
'import/no-named-as-default': 'off',
'import/namespace': [2, { allowComputed: true }],
'import/no-named-as-default-member': 'off',
'import/no-unresolved': [2, { ignore: ['ant-design-vue'] }],
'comma-dangle': [2, 'always-multiline'],
'no-var': 'error',
'no-console': [2, { allow: ['warn', 'error'] }],
'object-shorthand': 2,
'no-unused-vars': [2, { ignoreRestSiblings: true, argsIgnorePattern: '^_' }],
'no-undef': 2,
camelcase: 'off',
'no-extra-boolean-cast': 'off',
semi: ['error', 'always'],
'vue/no-v-html': 'off',
'vue/require-explicit-emits': 'off',
'vue/require-prop-types': 'off',
'vue/require-default-prop': 'off',
'vue/no-reserved-keys': 'off',
'vue/comment-directive': 'off',
'vue/prop-name-casing': 'off',
'vue/one-component-per-file': 'off',
'vue/custom-event-name-casing': 'off',
'vue/v-on-event-hyphenation': 'off',
'vue/max-attributes-per-line': [
2,
{
singleline: 20,
multiline: 1,
},
],
'vue/multi-word-component-names': 'off',
},
};

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
*.jsx linguist-language=Vue
*.tsx linguist-language=Vue

5
.github/FUNDING.yml vendored
View File

@ -1,5 +0,0 @@
# These are supported funding model platforms
github: # [tangjinzhou]
open_collective: ant-design-vue
patreon: tangjinzhou

View File

@ -1,17 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Create new issue
url: https://vuecomponent.github.io/issue-helper/
about: Please use the following link to create a new issue.
- name: Patreon
url: https://www.patreon.com/tangjinzhou
about: Love Ant Design Vue? Please consider supporting us via Patreon.
- name: Open Collective
url: https://opencollective.com/ant-design-vue/donate
about: Love Ant Design Vue? Please consider supporting us via Open Collective.
- name: Paypal
url: https://www.paypal.me/tangjinzhou
about: Love Ant Design Vue? Please consider supporting us via Paypal.
- name: 支付宝/微信 赞助
url: https://aliyuncdn.antdv.com/alipay-and-wechat.png
about: Ant Design Vue 的健康持续发展需要您的支持,🙏

View File

@ -1,50 +0,0 @@
首先,感谢你的贡献! 😄
新特性请提交至 feature 分支,其余可提交至 main 分支。在一个维护者审核通过后合并。请确保填写以下 pull request 的信息,谢谢!~
[[English Template / 英文模板](./pr_en.md)]
### 这个变动的性质是
- [ ] 新特性提交
- [ ] 日常 bug 修复
- [ ] 站点、文档改进
- [ ] 组件样式改进
- [ ] TypeScript 定义更新
- [ ] 重构
- [ ] 代码风格优化
- [ ] 分支合并
- [ ] 其他改动(是关于什么的改动?)
### 需求背景
> 1. 描述相关需求的来源。
> 2. 要解决的问题。
> 3. 相关的 issue 讨论链接。
### 实现方案和 API非新功能可选
> 1. 基本的解决思路和其他可选方案。
> 2. 列出最终的 API 实现和用法。
> 3. 涉及 UI/交互变动需要有截图或 GIF。
### 对用户的影响和可能的风险(非新功能可选)
> 1. 这个改动对用户端是否有影响?影响的方面有哪些?
> 2. 是否有可能隐含的 break change 和其他风险?
### Changelog 描述(非新功能可选)
> 1. 英文描述
> 2. 中文描述(可选)
### 请求合并前的自查清单
- [ ] 文档已补充或无须补充
- [ ] 代码演示已提供或无须提供
- [ ] TypeScript 定义已补充或无须补充
- [ ] Changelog 已提供或无须提供
### 后续计划(非新功能可选)
> 如果这个提交后面还有相关的其他提交和跟进信息,可以写在这里。

View File

@ -1,51 +0,0 @@
First of all, thank you for your contribution! 😄
New feature please send pull request to feature branch, and rest to main branch. Pull request will be merged after one of collaborators approve. Please makes sure that these form are filled before submitting your pull request, thank you!
[[中文版模板 / Chinese template](./pr_cn.md)]
### This is a ...
- [ ] New feature
- [ ] Bug fix
- [ ] Site / document update
- [ ] Component style update
- [ ] TypeScript definition update
- [ ] Refactoring
- [ ] Code style optimization
- [ ] Branch merge
- [ ] Other (about what?)
### What's the background?
> 1. Describe the source of requirement.
> 2. Resolve what problem.
> 3. Related issue link.
### API Realization (Optional if not new feature)
> 1. Basic thought of solution and other optional proposal.
> 2. List final API realization and usage sample.
> 3. GIF or snapshot should be provided if includes UI/interactive modification.
### What's the effect? (Optional if not new feature)
> 1. Does this PR affect user? Which part will be affected?
> 2. What will say in changelog?
> 3. Does this PR contains potential break change or other risk?
### Changelog description (Optional if not new feature)
> 1. English description
> 2. Chinese description (optional)
### Self Check before Merge
- [ ] Doc is updated/provided or not needed
- [ ] Demo is updated/provided or not needed
- [ ] TypeScript definition is updated/provided or not needed
- [ ] Changelog is provided or not needed
### Additional Plan? (Optional if not new feature)
> If this PR related with other PR or following info. You can type here.

View File

@ -1,14 +0,0 @@
comment: "Your issue has been closed because it does not conform to our issue requirements. Please use the [Issue Helper](https://vuecomponent.github.io/issue-helper/) to create an issue, thank you! <br/><br/> 为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。你可以通过 [issue 助手](https://vuecomponent.github.io/issue-helper/) 来创建 issue 以方便我们定位错误。谢谢配合!"
issueConfigs:
- content:
- "<!-- generated by issue-helper. DO NOT REMOVE -->"
- content:
- "Version"
- "Environment"
- "Reproduction link"
- "Steps to reproduce"
- "What is expected"
- "What is actually happening"
- content:
- "What problem does this feature solve"
- "What does the proposed API look like"

View File

@ -1,76 +0,0 @@
name: codecov
on: [push]
jobs:
setup:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: cache package-lock.json
uses: actions/cache@v1
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: create package-lock.json
run: npm i --package-lock-only --ignore-scripts
- name: hack for singe file
run: |
if [ ! -d "package-temp-dir" ]; then
mkdir package-temp-dir
fi
cp package-lock.json package-temp-dir
- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: install
if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
run: npm ci
node:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
# with:
# token: ${{ secrets.ACCESS_TOKEN }}
# - name: Checkout submodules
# uses: actions/checkout@v2
# with:
# repository: tangjinzhou/antdv-demo
# token: ${{ secrets.ACCESS_TOKEN }}
# path: antdv-demo
# submodules: true
- name: restore cache from package-lock.json
uses: actions/cache@v1
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: Generate coverage report
run: npm test
env:
COVERAGE: "true"
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
needs: setup

View File

@ -1,14 +0,0 @@
name: Emoji Helper
on:
release:
types: [published]
jobs:
emoji:
runs-on: ubuntu-latest
steps:
- uses: actions-cool/emoji-helper@v1.0.0
with:
type: 'release'
emoji: '+1, laugh, heart, hooray, rocket, eyes'

View File

@ -1,23 +0,0 @@
name: Issue Close Require
on:
schedule:
- cron: "0 0 * * *"
permissions:
contents: read
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: '🤔 Need Reproduce'
inactive-day: 7
body: |
Since the issue was labeled with `Need Reproduce`, but no response in 7 days. This issue will be closed. If you have any questions, you can comment and reply.
由于该 issue 被标记为需要复现信息,却 7 天未收到回应。现关闭 issue若有任何问题可评论回复。

View File

@ -1,76 +0,0 @@
name: Issue Labeled
on:
issues:
types: [labeled]
permissions:
contents: read
jobs:
issue-labeled:
permissions:
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: Need Reproduce
if: github.event.label.name == '🤔 Need Reproduce'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking this [link for vue2](https://codesandbox.io/s/2wpk21kzvr)、 [link for vue3](https://codesandbox.io/s/agitated-franklin-1w72v) or a minimal GitHub repository. Make sure to choose the correct version.
你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 [此处 for vue2](https://codesandbox.io/s/2wpk21kzvr)、 [此处 for vue3](https://codesandbox.io/s/agitated-franklin-1w72v) 创建一个 codesandbox 或者提供一个最小化的 GitHub 仓库。请确保选择准确的版本。
- name: help wanted
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to send us a Pull Request for it. Please send your Pull Request to proper branch, fill the Pull Request Template here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!
你好 @${{ github.event.issue.user.login }},我们完全同意你的提议/反馈,欢迎直接在此仓库创建一个 Pull Request 来解决这个问题。请将 Pull Request 发到正确的分支,务必填写 Pull Request 内的预设模板,提供改动所需相应的 changelog、TypeScript 定义、测试用例、文档等,并确保 CI 通过,我们会尽快进行 Review提前感谢和期待您的贡献。
- name: Usage
if: github.event.label.name == 'Usage'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}, we use GitHub issues to trace bugs or discuss plans of Ant Design Vue. So, please don't ask usage questions here. You can try to open a new discussion in [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](http://stackoverflow.com/questions/) or [Segment Fault](https://segmentfault.com).
你好 @${{ github.event.issue.user.login }}Ant Design Vue Issue 板块是用于 bug 反馈与需求讨论的地方。请勿询问如何使用的问题,你可以试着在 [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions) 新开一个 discussion选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](http://stackoverflow.com/questions/) 或者 [Segment Fault](https://segmentfault.com/) 中提问。
- name: 1.x
if: github.event.label.name == '1.x'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hi @${{ github.event.issue.user.login }}. Current version (1.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.
你好 @${{ github.event.issue.user.login }}当前版本1.x已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。
- name: 2.x
if: github.event.label.name == '2.x'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hi @${{ github.event.issue.user.login }}. Current version (2.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.
你好 @${{ github.event.issue.user.login }}当前版本2.x已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。

View File

@ -1,34 +0,0 @@
name: Issue Open Check
on:
issues:
types: [opened]
permissions:
contents: read
jobs:
issue-open-check:
permissions:
contents: read # for visiky/dingtalk-release-notify to get latest release
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- uses: actions-cool/check-user-permission@v1.0.0
id: checkUser
with:
require: 'write'
- name: check invalid
if: (contains(github.event.issue.body, 'issue-helper') == false) && (steps.checkUser.outputs.result == 'false')
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,add-labels,close-issue'
issue-number: ${{ github.event.issue.number }}
labels: 'Invalid'
body: |
Hello @${{ github.event.issue.user.login }}, your issue has been closed because it does not conform to our issue requirements. Please use the [Issue Helper](https://vuecomponent.github.io/issue-helper/) to create an issue, thank you!
你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。你可以通过 [issue 助手](https://vuecomponent.github.io/issue-helper/) 来创建 issue 以方便我们定位错误。谢谢配合!

View File

@ -1,23 +0,0 @@
name: 'Lock threads'
on:
schedule:
- cron: '0 0 * * *'
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '365'
issue-lock-labels: 'outdated'
issue-lock-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
pr-lock-comment: >
This pull request has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.

View File

@ -1,19 +0,0 @@
name: "Close stale issues"
on:
schedule:
- cron: "30 1 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
exempt-issue-labels: 'bug,enhancement'
days-before-stale: 60
days-before-close: 7

View File

@ -1,115 +0,0 @@
name: test
on: [push, pull_request]
jobs:
setup:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: cache package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: create package-lock.json
run: npm i --package-lock-only --ignore-scripts
- name: hack for singe file
run: |
if [ ! -d "package-temp-dir" ]; then
mkdir package-temp-dir
fi
cp package-lock.json package-temp-dir
- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: install
if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
run: npm ci
compile:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: restore cache from package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: cache lib
uses: actions/cache@v2
with:
path: lib
key: lib-${{ github.sha }}
- name: cache es
uses: actions/cache@v2
with:
path: es
key: es-${{ github.sha }}
- name: compile
run: npm run compile
needs: setup
lint:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: restore cache from package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: lint
run: npm run lint
needs: setup
node:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: restore cache from package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: test
run: npm test
needs: setup

27
.gitignore vendored
View File

@ -36,6 +36,9 @@ build/Release
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
@ -52,35 +55,13 @@ jspm_packages/
.yarn-integrity
# dotenv environment variables file
.vscode
.env
.idea
.DS_Store
dist
lib
es
/locale
_site
yarn.lock
package-lock.json
pnpm-lock.yaml
/coverage
site-dist
# 备份文件
/components/test/*
list.txt
site/dev.js
# IDE 语法提示临时文件
vetur/
report.html
site/src/router/demoRoutes.js
components/version/version.ts
components/version/version.tsx
components/version/token.json
components/version/token-meta.json
~component-api.json

1
.husky/.gitignore vendored
View File

@ -1 +0,0 @@
_

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install pretty-quick --staged

View File

@ -1,7 +0,0 @@
{
"hooks": {
"pre-commit": "pretty-quick --staged",
"pre-publish": "npm run lint",
"commit-msg": "commitlint -x @commitlint/config-conventional -e $GIT_PARAMS"
}
}

View File

@ -1,60 +0,0 @@
const libDir = process.env.LIB_DIR;
const transformIgnorePatterns = [
'/dist/',
// Ignore modules without es dir.
// Update: @babel/runtime should also be transformed
// 'node_modules/(?!.*(@babel|lodash-es))',
'node_modules/(?!@ant-design/icons-vue|@ant-design/icons-svg|lodash-es)/',
];
const testPathIgnorePatterns = ['/node_modules/', 'node'];
function getTestRegex(libDir) {
if (libDir === 'dist') {
return 'demo\\.test\\.js$';
}
return '.*\\.test\\.(j|t)sx?$';
}
module.exports = {
verbose: true,
setupFiles: ['./tests/setup.js'],
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'vue', 'md', 'jpg'],
modulePathIgnorePatterns: ['/_site/'],
testPathIgnorePatterns: testPathIgnorePatterns,
transform: {
'\\.(vue|md)$': '<rootDir>/node_modules/@vue/vue3-jest',
'\\.(js|jsx)$': '<rootDir>/node_modules/babel-jest',
'\\.(ts|tsx)$': '<rootDir>/node_modules/ts-jest',
'\\.svg$': '<rootDir>/node_modules/jest-transform-stub',
},
testRegex: getTestRegex(libDir),
moduleNameMapper: {
'^@/(.*)$/': '<rootDir>/$1',
'^ant-design-vue$': '<rootDir>/components/index',
'^ant-design-vue/es/(.*)$': '<rootDir>/components/$1',
},
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
collectCoverage: process.env.COVERAGE === 'true',
collectCoverageFrom: [
'components/**/*.{js,jsx,vue}',
'!components/*/__tests__/**/type.{js,jsx}',
'!components/vc-*/**/*',
'!components/*/demo/**/*',
'!components/_util/**/*',
'!components/align/**/*',
'!components/trigger/**/*',
'!**/node_modules/**',
],
testEnvironment: 'jsdom',
testEnvironmentOptions: {
url: 'http://localhost',
customExportConditions: ['node', 'node-addons'],
},
transformIgnorePatterns,
globals: {
'ts-jest': {
babelConfig: true,
},
},
};

1
.npmrc
View File

@ -1 +0,0 @@
enable-pre-post-scripts=true

View File

@ -1,31 +0,0 @@
**/*.svg
lib/
es/
dist/
_site/
coverage/
CNAME
LICENSE
yarn.lock
netlify.toml
yarn-error.log
*.sh
*.snap
.gitignore
.npmignore
.prettierignore
.DS_Store
.editorconfig
.eslintignore
**/*.yml
**/assets
.gitattributes
.stylelintrc
.vcmrc
.png
.npmrc.template
.huskyrc
.gitmodules
*.png
v2-doc/

View File

@ -1,17 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"printWidth": 100,
"proseWrap": "never",
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
]
}

View File

@ -1,5 +1,6 @@
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
"extends": "stylelint-config-standard",
"ignoreFiles": "./components/**",
"rules": {
"comment-empty-line-before": null,
"declaration-empty-line-before": null,

View File

@ -1,43 +0,0 @@
{
"extends": [
"stylelint-config-standard",
"stylelint-config-rational-order",
"stylelint-config-prettier"
],
"customSyntax": "postcss-less",
"plugins": ["stylelint-declaration-block-no-ignored-properties"],
"rules": {
"function-name-case": ["lower"],
"function-no-unknown": [
true,
{
"ignoreFunctions": [
"fade",
"fadeout",
"tint",
"darken",
"ceil",
"fadein",
"floor",
"unit",
"shade",
"lighten",
"percentage",
"-"
]
}
],
"import-notation": null,
"no-descending-specificity": null,
"no-invalid-position-at-import-rule": null,
"declaration-empty-line-before": null,
"keyframes-name-pattern": null,
"custom-property-pattern": null,
"number-max-precision": 8,
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"selector-class-pattern": null,
"selector-id-pattern": null,
"selector-not-notation": null
}
}

9
.travis.yml Normal file
View File

@ -0,0 +1,9 @@
language: node_js
sudo: required
node_js:
- 8.2.1
script:
- bash ./scripts/deploy-to-gh-pages.sh
env:
matrix:
secure: PBbJaS48HA/mkj9PuGuRxs00DEJR77XfuPdSlTvCq0QxLIR6wIO+t3LLJdOQctZIX6KWBR/Zq3zSn5bRxgPIaRcoyuEU25ga4cexJMEh1ymE23uTiDcnWwWN0X1jZKGuHPvqVKjyToAv6XW24mTXNvEAqD2uL101JxBseoWJ/2VtyOjJFJwcGbw+MTLymWCZiAF10w+k0SyigawaxZLlYL9LZXv4w3oCjCwuiTD/T6rvyT3wGQzXx7/P7XQGL4el4lE7leuK5m2PhWvX2S3t2FRpoZPw0DINJu5XzuBr3DSMErQjCrP4Ep8iqW8pGGLkoXbcxK3/K+uSy0k+DdBN7jRgnnOeLpqeVUSMaM6LRnl2XyDWL3dKpVbEzZaFkRTmAwdbgYjI+7Enn3/GtseMASo/gK47m2k+kE/msoqwpTGLC5DBOBKxdNShdFnEbOxLUUiVNgoZRXbj6VhdueqK89LsMDsnxzmFtrU8Ytgv8wJsFd5IkIhCStmQ9bdTqER659hd1Qqdh6Qe36AfpZcetOLr86Z++CSwA/pZbLPeEVrfCHDh6V3DPQXG+Zlf/m60OAmhosJ+4dxZwRnR8LnaDFZ+uLYMz+vJGeOtFHvczz7TW4mznjguLE51crG+mkBGT2dx1UUg7zs41lz3GtH9WY8cSG4y5ryjDl6YkXwoiZI=

17
.vcmrc
View File

@ -1,17 +0,0 @@
{
"helpMessage": "\nPlease fix your commit message (and consider using https://www.npmjs.com/package/commitizen)\n",
"types": [
"feat",
"fix",
"docs",
"style",
"refactor",
"perf",
"test",
"chore",
"revert",
"ci"
],
"warnOnFail": false,
"autoFix": false
}

42
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,42 @@
//
{
"eslint.enable": true,
"eslint.options": {
"extensions": [
".js",
".jsx",
".vue"
],
"configFile": ".eslintrc"
},
"eslint.validate": [
{
"language": "html",
"autoFix": true
},
{
"language": "vue",
"autoFix": true
},
{
"language": "javascript",
"autoFix": true
},
{
"language": "javascriptreact",
"autoFix": true
}
],
"emmet.syntaxProfiles": {
"vue-html": "html",
"vue": "html"
},
"eslint.autoFixOnSave": true,
"vetur.validation.template": true,
"vetur.format.html.wrap_line_length": 60,
"vetur.format.js.InsertSpaceBeforeFunctionParenthesis": true,
"stylefmt.config": {
"fix": true
},
"editor.tabSize": 2
}

View File

@ -1,55 +0,0 @@
<h1 align="center">Sponsors &amp; Backers</h1>
<br><br>
<h2 align="center">企业赞助</h2>
<p align="center">
<a href="http://www.powerproject.com.cn/" target="_blank"><img width="193" src="http://www.powerproject.com.cn/wp-content/uploads/2019/08/2019080215041192.png" title="donation by wechat"></a>
</p>
<h2 align="center">Sponsors</h2>
<p align="center">
<a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
</p>
<h2 align="center">Backers</h2>
<p align="center">
<a href="https://github.com/chuzhixin/vue-admin-beautiful" target="_blank"><img width="64" style="border-radius: 50%;" src="https://gitee.com/chu1204505056/image/raw/master/vue-admin-beautiful.png" title="vue-admin-beautiful"></a>
<a href="https://github.com/limichange" target="_blank"><img width="64" style="border-radius: 50%;" src="https://avatars0.githubusercontent.com/u/1947344?s=400&v=4" title="limichange donation total 24$ by qq from 2018.9"></a>
<a href="https://opencollective.com/ant-design-vue/backer/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/1/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/2/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/3/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/4/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/5/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/6/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/7/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/8/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/9/avatar.svg"></a>
<a href="https://opencollective.com/ant-design-vue/backer/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/10/avatar.svg"></a>
</p>
<h2 align="center">Patreon</h2>
<p align="center">
<a href="https://www.mokeyjay.com" target="_blank"><img width="64" style="border-radius: 50%;" src="https://www.mokeyjay.com/headimg.png" title="donation by Patreon"></a>
</p>
<h2 align="center">支付宝/微信</h2>
### 使用支付宝/微信的赞助的用户,如需要添加名单,赞助后可发 github 账号到邮箱(antdv@foxmail.com)
- [fastgoo](https://github.com/fastgoo)
- [sendya](https://github.com/sendya)
- [limichange](https://github.com/limichange)
- [LvHang](https://github.com/184005306)

View File

@ -1,239 +1,19 @@
# Change Log (The following content is translated by Google)
`ant-design-vue` strictly follows [Semantic Versioning 2.0.0](http://semver.org/).
#### Release Schedule
- Weekly release: patch version at the end of every week for routine bugfix (anytime for urgent bugfix).
- Monthly release: minor version at the end of every month for new features.
- Major version release is not included in this schedule for breaking change and new features.
# Change Log
---
## 0.4.0
## 4.2.6
#### Layout
- 🐞 Fix Modal component aria-hidden error problem under chrome [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823)
- 🐞 Fix the problem that the built-in input method of Safari automatically fills in the decimal point when inputting Chinese [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918)
- 🐞 Fix InputNumber component disabled style problem [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776)
- 🐞 Fix Select cannot lose focus problem [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819)
- add `layout` component
## 4.2.5
#### Others
- 🐞 Fix Empty component memory leak problem
- 🐞 Fix Image width & height property not working problem
- support use [Vue.use(antd)](https://github.com/vueComponent/ant-design/issues/3)
## 4.2.4
- 🐞 Fix Wave memory leak problem
## 0.3.1
## 4.2.3
#### Features
- 🌟 TourStep custom Button, support function children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
- 🐞 Fix the problem that the input value is hidden in Select and Cascader search multi-select mode [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
## 4.2.2
- 🐞 Fix TreeSelect placeholder slot invalid [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
- 🐞 Fix Tree slot responsive invalid issue [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
- 🐞 Fix FloatButton target type error issue [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
- 🐞 Fix FormItem className error issue [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
- 🐞 Fix Input Cannot input problem under lazy [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
- 🐞 Fix the problem that placeholder is not hidden when inputting Chinese in Select [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
- 🐞 Fix the problem that the pop-up window flashes when clicking the preset option in DatePicker [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
## 4.2.1
- 🐞 fix Input clear action error [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
## 4.2.0
- 🌟 Optimize the textColor change when the layout component switches to dark mode [#7498](https://github.com/vueComponent/ant-design-vue/issues/7498)
- 🌟 Tooltip added arrow hidden configuration [#7459](https://github.com/vueComponent/ant-design-vue/issues/7459)
- 🌟 Optimize Table hover performance [#7451](https://github.com/vueComponent/ant-design-vue/issues/7451)
- 🐞 Fixed the problem of changing the model during useForm verification, resulting in verification errors [#ffd4d8](https://github.com/vueComponent/ant-design-vue/commit/ffd4d8fe927f9ea40cbb6358ad997c447bd9a74e)
- 🐞 Fix Tabs folding calculation error issue [#7491](https://github.com/vueComponent/ant-design-vue/issues/7491)
- 🐞 Fix Qrcode missing type hint issue [#7502](https://github.com/vueComponent/ant-design-vue/issues/7502)
- 🐞 Fix Menu rendering error under SSR [#7349](https://github.com/vueComponent/ant-design-vue/issues/7349)
- 🐞 Fix Select and Cascader rendering errors under SSR [#7377](https://github.com/vueComponent/ant-design-vue/issues/7377)
- 🐞 Fix AutoComplete missing option slot declaration issue [#7396](https://github.com/vueComponent/ant-design-vue/issues/7396)
- 🐞 Fix Textarea autoSize not taking effect [#7478](https://github.com/vueComponent/ant-design-vue/issues/7478)
- 🐞 Fix Paginations Enter key triggering two page turns [#7368](https://github.com/vueComponent/ant-design-vue/issues/7368)
- 🐞 Fix the problem of Chinese input in the input box [#7391](https://github.com/vueComponent/ant-design-vue/issues/7391)[#7516](https://github.com/vueComponent/ant- design-vue/issues/7516)
- 🐞 Fix Carousel beforeChange current parameter error issue [#7419](https://github.com/vueComponent/ant-design-vue/issues/7419)
## 4.1.2
- 🐞 Fix table resize error reporting under vue 3.4 [#7291](https://github.com/vueComponent/ant-design-vue/issues/7291)
- 🐞 Fix the problem that the Segmented title attribute is not displayed [#7302](https://github.com/vueComponent/ant-design-vue/issues/7302)
## 4.1.1
- 🌟 QRcode adds scanned status [#7242](https://github.com/vueComponent/ant-design-vue/issues/7242)
- 🐞 Fix css prefix issue in nuxt [#7256](https://github.com/vueComponent/ant-design-vue/issues/7256)
- 🐞 Fix dropdown closing issue [#7246](https://github.com/vueComponent/ant-design-vue/issues/7246)
- 🐞 Fix divider vertical dashed not display issue [#7218](https://github.com/vueComponent/ant-design-vue/issues/7218)
- 🐞 Fix hook mode message console warning issue [#7281](https://github.com/vueComponent/ant-design-vue/issues/7281)
- 🐞 Fix table expansion error reporting under vue 3.4 [#7265](https://github.com/vueComponent/ant-design-vue/issues/7265)
- 🐞 Fix table group filter status error issue [#7233](https://github.com/vueComponent/ant-design-vue/issues/7233)
## 4.1.0
- 🐞 support vue 3.4 [#7239](https://github.com/vueComponent/ant-design-vue/issues/7239)
## 4.0.8
- 🐞 Fix theme responsiveness failure issue under Nuxt [#7180](https://github.com/vueComponent/ant-design-vue/issues/7180)
- 🐞 Fix error reporting caused by Wave [#7108](https://github.com/vueComponent/ant-design-vue/issues/7108)
- 🐞 Fix Upload disabled inheritance issue [#7110](https://github.com/vueComponent/ant-design-vue/issues/7110)
- 🐞 Fix Tooltip popupAlign not taking effect [#7112](https://github.com/vueComponent/ant-design-vue/issues/7112)
- 🐞 Fix Typography flashing problem [#7146](https://github.com/vueComponent/ant-design-vue/issues/7146)
- 🐞 Fix the issue that RangePicker prevIcon nextIcon does not take effect [#7127](https://github.com/vueComponent/ant-design-vue/issues/7127)
- 🐞 Fixed the issue of watermark not monitoring child element changes [#7149](https://github.com/vueComponent/ant-design-vue/issues/7149)
- 🐞 Fix Menu animation missing issue [#7130](https://github.com/vueComponent/ant-design-vue/issues/7130)
- 🐞 Fix the cursor change issue when TextArea autosize [#7121](https://github.com/vueComponent/ant-design-vue/issues/7121)
## 4.0.7
- 🌟 Added Flex component [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
- 🌟 ConfigProvider adds wave configuration [#7036](https://github.com/vueComponent/ant-design-vue/issues/7036)
- 🌟 Watermark supports dark mode [#7067](https://github.com/vueComponent/ant-design-vue/issues/7067)
- 🐞 Fix Space duplicate Key problem [#7048](https://github.com/vueComponent/ant-design-vue/issues/7048)
- 🐞 Fix Upload disabled priority error issue [#7047](https://github.com/vueComponent/ant-design-vue/issues/7047)
- 🐞 Fix Carousel rendering error in jsx [#7077](https://github.com/vueComponent/ant-design-vue/issues/7077)
- 🐞 Fix Message offset position problem [#7093](https://github.com/vueComponent/ant-design-vue/issues/7093)
- 🐞 Fix the problem of animation failure when using Collapse custom prefix [#7074](https://github.com/vueComponent/ant-design-vue/issues/7074)
## 4.0.6
- 🐞 Fix the Dropdown onVisibleChange failure issue introduced in 4.0.4 [#7031](https://github.com/vueComponent/ant-design-vue/issues/7031)
## 4.0.5
- 🐞 Fix cssinjs performance issue [#7023](https://github.com/vueComponent/ant-design-vue/issues/7023)
## 4.0.4
- 🌟 Added esm target file
- 🌟 Added tooltip attribute to FormItem [#7014](https://github.com/vueComponent/ant-design-vue/issues/7014)
- 🐞 Fix useMessage getContainer not taking effect [#6942](https://github.com/vueComponent/ant-design-vue/issues/6942)
- 🐞 Fix the problem of Image triggering onPreviewVisibleChange event multiple times [#6945](https://github.com/vueComponent/ant-design-vue/issues/6945)
- 🐞 Fix the problem that Checkbox global disabled does not take effect [#6970](https://github.com/vueComponent/ant-design-vue/issues/6970)
- 🐞 Fix Drawer contentWrapperStyle not taking effect [#6983](https://github.com/vueComponent/ant-design-vue/issues/6983)
- 🐞 Optimize Select Dropdown and other drop-down list scroll bar display hidden logic [#6987](https://github.com/vueComponent/ant-design-vue/issues/6987)
- 🐞 Fix the problem of hiding when there are components such as input in the drop-down list such as Select Dropdown [#7020](https://github.com/vueComponent/ant-design-vue/issues/7020)
## 4.0.3
- 🐞 Fix the problem of style loss under shadow Dom [#6912](https://github.com/vueComponent/ant-design-vue/issues/6912)
- 🐞 Upgrade Icon dependency and fix icon css missing problem under shadow Dom [#6914](https://github.com/vueComponent/ant-design-vue/issues/6914)
## 4.0.2
- 🐞 Fix useMessage causing body to be removed [#6880](https://github.com/vueComponent/ant-design-vue/issues/6880)
- 🐞 Fix the problem that the water ripple effect does not disappear after Button loading is switched [#6895](https://github.com/vueComponent/ant-design-vue/issues/6895)
- 🐞 Fixed the problem that flip does not reset after Image is closed [#6913](https://github.com/vueComponent/ant-design-vue/issues/6913)
- 🐞 Fix ImageGroup animation effect loss problem [#6898](https://github.com/vueComponent/ant-design-vue/issues/6898)
- 🐞 Fix Modal missing onUpdate:open attribute declaration [#6876](https://github.com/vueComponent/ant-design-vue/issues/6876)
- 🐞 Fixed the issue of multiple clicks being triggered at the edge of Transfer's Checkbox [#6902](https://github.com/vueComponent/ant-design-vue/issues/6902)
## 4.0.1
- 🌟 FloatButton add Badge support [#6738](https://github.com/vueComponent/ant-design-vue/issues/6738)
- 🌟 Image preview zoom in and out sensitivity adjustment [#6784](https://github.com/vueComponent/ant-design-vue/issues/6784)
- 🌟 Add flip feature to Image [#6785](https://github.com/vueComponent/ant-design-vue/issues/6785)
- 🌟 Add App component to provide context [#6735](https://github.com/vueComponent/ant-design-vue/issues/6735)
- 🌟 Style extraction feature for SSR [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🌟 Support px2rem [#6817](https://github.com/vueComponent/ant-design-vue/issues/6817)
- 🌟 Tag supports borderless mode [#6819](https://github.com/vueComponent/ant-design-vue/issues/6819)
- 🌟 Avatar group mode supports shape [#6822](https://github.com/vueComponent/ant-design-vue/issues/6822)
- 🌟 AutoComplete supports borderless and custom clearIcon [#6829](https://github.com/vueComponent/ant-design-vue/issues/6829)
- 🌟 InputPassword supports controlled visible [#6863](https://github.com/vueComponent/ant-design-vue/issues/6863)
- 🐞 Fix the style misalignment problem when InputGroup is large [#6866](https://github.com/vueComponent/ant-design-vue/issues/6866)
- 🐞 Fix the problem that Checkable Tag cannot customize class [#6854](https://github.com/vueComponent/ant-design-vue/issues/6854)
- 🐞 Fix the rendering problem in Tabs animation mode [#6855](https://github.com/vueComponent/ant-design-vue/issues/6855)
- 🐞 Fix the problem that the Image height attribute does not take effect [#6840](https://github.com/vueComponent/ant-design-vue/issues/6840)
- 🐞 Fix InputNumber trigger mouseup event [#6772](https://github.com/vueComponent/ant-design-vue/issues/6772)
- 🐞 Fix the Dropdown style problem when Tabs are collapsed [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🐞 Fix Table expandedRowRender property does not take effect [#6783](https://github.com/vueComponent/ant-design-vue/issues/6783)
- 🐞 Fix dayjs not packaged into dist [#6767](https://github.com/vueComponent/ant-design-vue/issues/6767)
- 🐞 Fix clipPath browser compatibility issue [#6770](https://github.com/vueComponent/ant-design-vue/issues/6770)
- 🐞 Fix Carousel autoplay responsive problem [#6768](https://github.com/vueComponent/ant-design-vue/issues/6768)
- 🐞 Fix PageHeader ghost style problem [#6761](https://github.com/vueComponent/ant-design-vue/issues/6761)
- 🐞 Fix Checkbox not triggering Form validation [#6741](https://github.com/vueComponent/ant-design-vue/issues/6741)
- 🐞 Fix the problem that the Input prefix attribute does not take effect [#6810](https://github.com/vueComponent/ant-design-vue/issues/6810)
- 🐞 Fix Badge style problem in Avatar [#6874](https://github.com/vueComponent/ant-design-vue/issues/6874)
## 4.0
### 🔥🔥🔥 4.0 official version released 🔥🔥🔥
### Design specification adjustment
- Basic rounded corner adjustment, changed from unified `2px` to four-level rounded corners, which are `2px` `4px` `6px` `8px` respectively, which are applied to different scenarios, for example, the rounded corners of the default size Button are adjusted to `6px`.
- Main color adjustment, changed from `#1890ff` to `#1677ff`.
- Overall shadow adjustment, from the original three-level shadow adjustment to two levels, which are used for resident page components (such as Card) and interactive feedback (such as Dropdown).
- Adjust the internal spacing of some components.
- Overall de-wireframing.
### Add 5 new components
- Segmented segment controller
- WaterMark watermark
- QrCode QR code
- FloatButton floating button
- Tour roaming guide
### Technical adjustments
- Deprecated less and adopted CSS-in-JS to better support dynamic themes.
- All less files are removed, and less variables no longer support leaking.
- css files are no longer included in the product. Since CSS-in-JS supports importing on demand, the original `ant-design-vue/dist/antd.css` has also been removed. If you need to reset some basic styles, please import `ant-design-vue/dist/reset .css`.
- If you need to reset the style of the component and don't want to introduce `ant-design-vue/dist/reset.css` to pollute the global style, you can try to use [App component](/components/app), to solve the problem that native elements do not have ant-design-vue specification style.
- Removed css variables and dynamic theme schemes built on top of it.
- LocaleProvider has been deprecated in 3.x (use `<ConfigProvider locale />` instead), we have completely removed the related directories `ant-design-vue/es/locale-provider`, `ant- design-vue/lib/locale-provider`.
- `babel-plugin-import` is no longer supported, CSS-in-JS itself has the ability to load on demand, no longer need plug-in support.
#### Component API adjustments
- The classname API of the component popup is unified to `popupClassName`, and similar APIs such as `dropdownClassName` will be replaced.
- AutoComplete component
- Cascader component
- Select component
- TreeSelect component
- TimePicker component
- DatePicker component
- Mentions component
- The controlled visibility API of the component popup is unified as `open`, and `visible` and other similar APIs will be replaced.
- Drawer component `visible` becomes `open`.
- Modal component `visible` becomes `open`.
- Dropdown component `visible` becomes `open`.
- Tooltip component `visible` becomes `open`.
- Tag component `visible` has been removed.
- Slider component `tooltip` related API converges to `tooltip` property.
- Table component `filterDropdownVisible` changed to `filterDropdownOpen`.
- `getPopupContainer`: All `getPopupContainer` needs to ensure that the returned div is unique.
- Drawer `style` and `class` are migrated to the Drawer popup area, and the original attributes are replaced by `rootClassName` and `rootStyle`.
#### Component refactoring and removal
- Remove the `locale-provider` directory. `LocaleProvider` has been removed in v4, please use `ConfigProvider` instead.
- Remove `xxxl` breakpoint attribute in grid layout. `xxxl` attribute has been removed in v4, you can use [theme customization](/docs/vue/customize-theme) to modify `screen[XS|SM|MD|LG|XL|XXL]` to modify the break Point value achieved.
- The BackTop component was deprecated in `4.0.0` and moved to the FloatButton floating button. If needed, it can be imported from FloatButton.
### [Upgrade Guide](/docs/vue/migration-v4)
## 3.x
Visit [GitHub](https://github.com/vueComponent/ant-design-vue/blob/3.x/CHANGELOG.zh-CN.md) `3.x` Change Log。
## 2.x
Visit [GitHub](https://github.com/vueComponent/ant-design-vue/blob/2.x/CHANGELOG.zh-CN.md) `2.x` Change Log。
## 1.x
Visit [GitHub](https://github.com/vueComponent/ant-design-vue/blob/1.x/CHANGELOG.en-US.md) to read change logs from `0.x` to `1.x`.
- first version, provide 45 [components](https://github.com/vueComponent/ant-design/blob/c7e83d6142f0c5e72ef8fe794620478e69a50a8e/site/components.js)

View File

@ -1,239 +1,20 @@
# 更新日志
`ant-design-vue` 严格遵循 [Semantic Versioning 2.0.0](http://semver.org/lang/zh-CN/) 语义化版本规范。
#### 发布周期
- 修订版本号:每周末会进行日常 bugfix 更新。(如果有紧急的 bugfix则任何时候都可发布
- 次版本号:每月发布一个带有新特性的向下兼容的版本。
- 主版本号:含有破坏性更新和新特性,不在发布周期内。
---
## 0.4.0
## 4.2.6
#### Layout
- 🐞 修复 Modal 组件在 chrome 下aria-hidden 报错问题 [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823)
- 🐞 修复 Safari 下自带输入法 input 组件输入中文时,自动填写小数点问题 [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918)
- 🐞 修复 InputNumber 组件 disabled 样式问题 [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776)
- 🐞 修复 Select 无法失焦问题 [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819)
- 新增 Layout 组件
## 4.2.5
#### 其它
- 🐞 修复 Empty 组件内存泄漏问题
- 🐞 修复 Image width & height 属性不生效问题
- 支持导入所有组件[Vue.use(antd)](https://github.com/vueComponent/ant-design/issues/3)
## 4.2.4
- 🐞 修复 Wave 内存泄漏问题
## 0.3.1
## 4.2.3
#### Features
- 🌟 TourStep 自定义 Button支持函数 children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
- 🐞 修复 Select 和 Cascader 搜索多选模式下,输入值被隐藏问题 [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
- 对外第一个版本提供常用45个[组件](https://github.com/vueComponent/ant-design/blob/c7e83d6142f0c5e72ef8fe794620478e69a50a8e/site/components.js)
## 4.2.2
- 🐞 修复 TreeSelect placeholder 插槽无效 [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
- 🐞 修复 Tree 插槽响应式无效问题 [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
- 🐞 修复 FloatButton target 类型错误问题 [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
- 🐞 修复 FormItem className 错误问题 [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
- 🐞 修复 Input lazy 下无法输入问题 [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
- 🐞 修复 Select 输入中文时placeholder 未隐藏问题 [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
- 🐞 修复 DatePicker 点击预设选项时,弹窗闪动问题 [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
## 4.2.1
- 🐞 修复 Input 清空操作才报错问题 [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
## 4.2.0
- 🌟 优化 layout 组件切换 dark 模式时 textColor 变化 [#7498](https://github.com/vueComponent/ant-design-vue/issues/7498)
- 🌟 Tooltip 新增 arrow 隐藏配置 [#7459](https://github.com/vueComponent/ant-design-vue/issues/7459)
- 🌟 优化 Table hover 性能 [#7451](https://github.com/vueComponent/ant-design-vue/issues/7451)
- 🐞 修复 useForm 校验时更改 model导致校验错误问题 [#ffd4d8](https://github.com/vueComponent/ant-design-vue/commit/ffd4d8fe927f9ea40cbb6358ad997c447bd9a74e)
- 🐞 修复 Tabs 折叠计算错误问题 [#7491](https://github.com/vueComponent/ant-design-vue/issues/7491)
- 🐞 修复 Qrcode 缺少类型提示问题 [#7502](https://github.com/vueComponent/ant-design-vue/issues/7502)
- 🐞 修复 Menu 在 SSR 下渲染错误问题 [#7349](https://github.com/vueComponent/ant-design-vue/issues/7349)
- 🐞 修复 Select、Cascader 在 SSR 下渲染错误问题 [#7377](https://github.com/vueComponent/ant-design-vue/issues/7377)
- 🐞 修复 AutoComplete 缺少 option slot 声明问题 [#7396](https://github.com/vueComponent/ant-design-vue/issues/7396)
- 🐞 修复 Textarea autoSize 不生效问题 [#7478](https://github.com/vueComponent/ant-design-vue/issues/7478)
- 🐞 修复 Pagination 回车键触发两次翻页问题 [#7368](https://github.com/vueComponent/ant-design-vue/issues/7368)
- 🐞 修复输入框输入中文问题 [#7391](https://github.com/vueComponent/ant-design-vue/issues/7391)[#7516](https://github.com/vueComponent/ant-design-vue/issues/7516)
- 🐞 修复 Carousel beforeChange current 参数错误问题 [#7419](https://github.com/vueComponent/ant-design-vue/issues/7419)
## 4.1.2
- 🐞 修复 table resize 在 vue 3.4 下报错问题 [#7291](https://github.com/vueComponent/ant-design-vue/issues/7291)
- 🐞 修复 Segmented title 属性不显示问题 [#7302](https://github.com/vueComponent/ant-design-vue/issues/7302)
## 4.1.1
- 🌟 QRcode 新增 scanned 状态 [#7242](https://github.com/vueComponent/ant-design-vue/issues/7242)
- 🐞 修复 css prefix 在 nuxt 问题 [#7256](https://github.com/vueComponent/ant-design-vue/issues/7256)
- 🐞 修复 dropdown 关闭问题 [#7246](https://github.com/vueComponent/ant-design-vue/issues/7246)
- 🐞 修复 divider vertical dashed 不显示问题 [#7218](https://github.com/vueComponent/ant-design-vue/issues/7218)
- 🐞 修复 hook 模式 message 控制台 warning 问题 [#7281](https://github.com/vueComponent/ant-design-vue/issues/7281)
- 🐞 修复 table 展开在 vue 3.4 下报错问题 [#7265](https://github.com/vueComponent/ant-design-vue/issues/7265)
- 🐞 修复 table group 过滤状态错误问题 [#7233](https://github.com/vueComponent/ant-design-vue/issues/7233)
## 4.1.0
- 🐞 适配 vue 3.4 [#7239](https://github.com/vueComponent/ant-design-vue/issues/7239)
## 4.0.8
- 🐞 修复在 Nuxt 下 theme 响应式失效问题 [#7180](https://github.com/vueComponent/ant-design-vue/issues/7180)
- 🐞 修复 Wave 引起的报错问题 [#7108](https://github.com/vueComponent/ant-design-vue/issues/7108)
- 🐞 修复 Upload disabled 继承问题 [#7110](https://github.com/vueComponent/ant-design-vue/issues/7110)
- 🐞 修复 Tooltip popupAlign 未生效问题 [#7112](https://github.com/vueComponent/ant-design-vue/issues/7112)
- 🐞 修复 Typography 闪动问题 [#7146](https://github.com/vueComponent/ant-design-vue/issues/7146)
- 🐞 修复 RangePicker prevIcon nextIcon 未生效问题 [#7127](https://github.com/vueComponent/ant-design-vue/issues/7127)
- 🐞 修复 watermark 未监听子元素变动问题 [#7149](https://github.com/vueComponent/ant-design-vue/issues/7149)
- 🐞 修复 Menu 动画丢失问题 [#7130](https://github.com/vueComponent/ant-design-vue/issues/7130)
- 🐞 修复 TextArea autosize 时光标变化问题 [#7121](https://github.com/vueComponent/ant-design-vue/issues/7121)
## 4.0.7
- 🌟 新增 Flex 组件 [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
- 🌟 ConfigProvider 新增 wave 配置 [#7036](https://github.com/vueComponent/ant-design-vue/issues/7036)
- 🌟 Watermark 支持暗黑模式 [#7067](https://github.com/vueComponent/ant-design-vue/issues/7067)
- 🐞 修复 Space 重复 Key 问题 [#7048](https://github.com/vueComponent/ant-design-vue/issues/7048)
- 🐞 修复 Upload disabled 优先级错误问题 [#7047](https://github.com/vueComponent/ant-design-vue/issues/7047)
- 🐞 修复 Carousel 在 jsx 中渲染错误问题 [#7077](https://github.com/vueComponent/ant-design-vue/issues/7077)
- 🐞 修复 Message 偏移位置问题 [#7093](https://github.com/vueComponent/ant-design-vue/issues/7093)
- 🐞 修复 Collapse 自定义 prefix 时动画失效问题 [#7074](https://github.com/vueComponent/ant-design-vue/issues/7074)
## 4.0.6
- 🐞 修复 4.0.4 引入的 Dropdown onVisibleChange 失效问题 [#7031](https://github.com/vueComponent/ant-design-vue/issues/7031)
## 4.0.5
- 🐞 修复 cssinjs 性能问题 [#7023](https://github.com/vueComponent/ant-design-vue/issues/7023)
## 4.0.4
- 🌟 新增 esm 目标文件
- 🌟 FormItem 新增 tooltip 属性 [#7014](https://github.com/vueComponent/ant-design-vue/issues/7014)
- 🐞 修复 useMessage getContainer 不生效问题 [#6942](https://github.com/vueComponent/ant-design-vue/issues/6942)
- 🐞 修复 Image 多次触发 onPreviewVisibleChange 事件问题 [#6945](https://github.com/vueComponent/ant-design-vue/issues/6945)
- 🐞 修复 Checkbox 全局 disabled 不生效问题 [#6970](https://github.com/vueComponent/ant-design-vue/issues/6970)
- 🐞 修复 Drawer contentWrapperStyle 不生效问题 [#6983](https://github.com/vueComponent/ant-design-vue/issues/6983)
- 🐞 优化 Select Dropdown 等下拉列表滚动条显示隐藏逻辑 [#6987](https://github.com/vueComponent/ant-design-vue/issues/6987)
- 🐞 修复 Select Dropdown 等下拉列表中有 input 等组件时,隐藏问题 [#7020](https://github.com/vueComponent/ant-design-vue/issues/7020)
## 4.0.3
- 🐞 修复 shadow Dom 下样式丢失问题 [#6912](https://github.com/vueComponent/ant-design-vue/issues/6912)
- 🐞 升级 Icon 依赖,修复 shadow Dom 下 icon css 丢失问题 [#6914](https://github.com/vueComponent/ant-design-vue/issues/6914)
## 4.0.2
- 🐞 修复 useMessage 导致 body 被移除问题 [#6880](https://github.com/vueComponent/ant-design-vue/issues/6880)
- 🐞 修复 Button loading 切换后,水波纹效果不消失问题 [#6895](https://github.com/vueComponent/ant-design-vue/issues/6895)
- 🐞 修复 Image 关闭后 flip 没有重置问题 [#6913](https://github.com/vueComponent/ant-design-vue/issues/6913)
- 🐞 修复 ImageGroup 动画效果丢失问题 [#6898](https://github.com/vueComponent/ant-design-vue/issues/6898)
- 🐞 修复 Modal 缺少 onUpdate:open 属性声明 [#6876](https://github.com/vueComponent/ant-design-vue/issues/6876)
- 🐞 修复 Transfer 的 Checkbox 边缘处会触发多次 click 问题 [#6902](https://github.com/vueComponent/ant-design-vue/issues/6902)
## 4.0.1
- 🌟 FloatButton 添加 Badge 支持 [#6738](https://github.com/vueComponent/ant-design-vue/issues/6738)
- 🌟 Image 预览放大缩小灵敏度调整 [#6784](https://github.com/vueComponent/ant-design-vue/issues/6784)
- 🌟 Image 新增翻转特性 [#6785](https://github.com/vueComponent/ant-design-vue/issues/6785)
- 🌟 新增 App 组件,用于提供上下文 [#6735](https://github.com/vueComponent/ant-design-vue/issues/6735)
- 🌟 样式抽离特性用于 SSR [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🌟 支持 px2rem [#6817](https://github.com/vueComponent/ant-design-vue/issues/6817)
- 🌟 Tag 支持无边框模式 [#6819](https://github.com/vueComponent/ant-design-vue/issues/6819)
- 🌟 Avatar group 模式支持 shape [#6822](https://github.com/vueComponent/ant-design-vue/issues/6822)
- 🌟 AutoComplete 支持无边框和自定义 clearIcon [#6829](https://github.com/vueComponent/ant-design-vue/issues/6829)
- 🌟 InputPassword 支持受控 visible [#6863](https://github.com/vueComponent/ant-design-vue/issues/6863)
- 🐞 修复 InputGroup 在 large 时样式错位问题 [#6866](https://github.com/vueComponent/ant-design-vue/issues/6866)
- 🐞 修复 Checkable Tag 无法自定义 class 问题 [#6854](https://github.com/vueComponent/ant-design-vue/issues/6854)
- 🐞 修复 Tabs 动画模式下渲染问题 [#6855](https://github.com/vueComponent/ant-design-vue/issues/6855)
- 🐞 修复 Image height 属性不生效问题 [#6840](https://github.com/vueComponent/ant-design-vue/issues/6840)
- 🐞 修复 InputNumber 触发 mouseup 事件问题 [#6772](https://github.com/vueComponent/ant-design-vue/issues/6772)
- 🐞 修复 Tabs 折叠时 Dropdown 样式问题 [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🐞 修复 Table expandedRowRender 属性不生效 [#6783](https://github.com/vueComponent/ant-design-vue/issues/6783)
- 🐞 修复 dayjs 未打包进 dist 问题 [#6767](https://github.com/vueComponent/ant-design-vue/issues/6767)
- 🐞 解决 clipPath 浏览器兼容问题 [#6770](https://github.com/vueComponent/ant-design-vue/issues/6770)
- 🐞 修复 Carousel autoplay 响应式问题 [#6768](https://github.com/vueComponent/ant-design-vue/issues/6768)
- 🐞 修复 PageHeader ghost 样式问题 [#6761](https://github.com/vueComponent/ant-design-vue/issues/6761)
- 🐞 修复 Checkbox 没有触发 Form 校验问题 [#6741](https://github.com/vueComponent/ant-design-vue/issues/6741)
- 🐞 修复 Input prefix 属性未生效问题 [#6810](https://github.com/vueComponent/ant-design-vue/issues/6810)
- 🐞 修复 Badge 在 Avatar 中样式问题 [#6874](https://github.com/vueComponent/ant-design-vue/issues/6874)
## 4.0
### 🔥🔥🔥 4.0 正式版发布 🔥🔥🔥
### 设计规范调整
- 基础圆角调整,由统一的 `2px` 改为四级圆角,分别为 `2px` `4px` `6px` `8px`,分别应用于不同场景,比如默认尺寸的 Button 的圆角调整为了 `6px`
- 主色调整,由 `#1890ff` 改为 `#1677ff`
- 整体阴影调整,由原本的三级阴影调整为两级,分别用于常驻页面的组件(如 Card和交互反馈如 Dropdown
- 部分组件内间距调整。
- 整体去线框化。
### 新增 5 个组件
- Segmented 分段控制器
- WaterMark 水印
- QrCode 二维码
- FloatButton 悬浮按钮
- Tour 漫游式引导
### 技术调整
- 弃用 less采用 CSS-in-JS更好地支持动态主题。
- 所有 less 文件全部移除less 变量不再支持透出。
- 产物中不再包含 css 文件。由于 CSS-in-JS 支持按需引入,原本的 `ant-design-vue/dist/antd.css` 也已经移除,如果需要重置一些基本样式请引入 `ant-design-vue/dist/reset.css`
- 如果需要组件重置样式,又不想引入 `ant-design-vue/dist/reset.css` 从而导致污染全局样式的话,可以尝试在应用最外层使用[App 组件](/components/app-cn),解决原生元素没有 ant-design-vue 规范样式的问题。
- 移除 css variables 以及在此之上构筑的动态主题方案。
- LocaleProvider 在 3.x 中已经废弃(使用 `<ConfigProvider locale />` 替代),我们在 4.x 里彻底移除了相关目录 `ant-design-vue/es/locale-provider`、`ant-design-vue/lib/locale-provider`。
- 不再支持 `babel-plugin-import`CSS-in-JS 本身具有按需加载的能力,不再需要插件支持。
#### 组件 API 调整
- 组件弹框的 classname API 统一为 `popupClassName``dropdownClassName` 等类似 API 都会被替换。
- AutoComplete 组件
- Cascader 组件
- Select 组件
- TreeSelect 组件
- TimePicker 组件
- DatePicker 组件
- Mentions 组件
- 组件弹框的受控可见 API 统一为 `open``visible` 等类似 API 都会被替换。
- Drawer 组件 `visible` 变为 `open`
- Modal 组件 `visible` 变为 `open`
- Dropdown 组件 `visible` 变为 `open`
- Tooltip 组件 `visible` 变为 `open`
- Tag 组件 `visible` 已移除。
- Slider 组件 `tooltip` 相关 API 收敛到 `tooltip` 属性中。
- Table 组件 `filterDropdownVisible` 变为 `filterDropdownOpen`
- `getPopupContainer`: 所有的 `getPopupContainer` 都需要保证返回的是唯一的 div。
- Drawer `style``class` 迁移至 Drawer 弹层区域上,原属性替换为 `rootClassName``rootStyle`
#### 组件重构与移除
- 移除 `locale-provider` 目录。`LocaleProvider` 在 v4 中已移除,请使用 `ConfigProvider` 替代。
- 移除栅格布局中的`xxxl`断点属性。 `xxxl`属性已经在 v4 被移除,您可以使用 [主题定制](/docs/vue/customize-theme-cn) 修改 `screen[XS|SM|MD|LG|XL|XXL]` 来修改断点值实现。
- BackTop 组件在 `4.0.0` 中废弃,移至 FloatButton 悬浮按钮中。如需使用,可以从 FloatButton 中引入。
### [升级指南](/docs/vue/migration-v4-cn)
## 3.x
去 [GitHub](https://github.com/vueComponent/ant-design-vue/blob/3.x/CHANGELOG.zh-CN.md) 查看 `3.x` 的 Change Log。
## 2.x
去 [GitHub](https://github.com/vueComponent/ant-design-vue/blob/2.x/CHANGELOG.zh-CN.md) 查看 `2.x` 的 Change Log。
## 1.x
去 [GitHub](https://github.com/vueComponent/ant-design-vue/blob/1.x/CHANGELOG.zh-CN.md) 查看 `0.x``1.x` 的 Change Log。

24
LICENSE
View File

@ -1,7 +1,7 @@
MIT License
Copyright (c) 2017-present ant-design-vue
Copyright (c) 2017-present vue-antd-ui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -44,25 +44,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
MIT License
Copyright (c) 2019-PRESENT Anthony Fu<https://github.com/antfu>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,120 +1,45 @@
<p align="center">
<a href="https://www.antdv.com/">
<img width="200" src="https://aliyuncdn.antdv.com/logo.png">
<a href="https://vuecomponent.github.io/ant-design/">
<img width="230" src="https://raw.githubusercontent.com/vueComponent/ant-design/master/logo.png">
</a>
</p>
<h1 align="center">
<a href="https://www.antdv.com/" target="_blank">Ant Design Vue</a>
</h1>
# [Ant Design Vue](https://vuecomponent.github.io/ant-design/)
[![Travis branch](https://api.travis-ci.org/vueComponent/ant-design.svg?branch=master)](https://travis-ci.org/vueComponent/ant-design)
[![Dependency Status](https://beta.gemnasium.com/badges/github.com/vueComponent/ant-design.svg)](https://beta.gemnasium.com/projects/github.com/vueComponent/ant-design)
[![npm package](https://img.shields.io/npm/v/vue-antd-ui.svg?style=flat)](https://www.npmjs.org/package/vue-antd-ui)
[![NPM downloads](http://img.shields.io/npm/dm/vue-antd-ui.svg?style=flat)](http://www.npmtrends.com/vue-antd-ui)
<div align="center">
基于 Ant Design 和 Vue 3 的企业级 UI 组件库
Ant Design 3.X 的 Vue 实现,开发和服务于企业级后台产品
![test](https://github.com/vueComponent/ant-design-vue/workflows/test/badge.svg) [![codecov](https://img.shields.io/codecov/c/github/vueComponent/ant-design-vue/master.svg?style=flat-square)](https://codecov.io/gh/vueComponent/ant-design-vue) [![npm package](https://img.shields.io/npm/v/ant-design-vue.svg?style=flat-square)](https://www.npmjs.org/package/ant-design-vue) [![NPM downloads](http://img.shields.io/npm/dm/ant-design-vue.svg?style=flat-square)](http://www.npmtrends.com/ant-design-vue) [![backers](https://opencollective.com/ant-design-vue/backers/badge.svg)](#backers) [![sponsors](https://opencollective.com/ant-design-vue/sponsors/badge.svg)](#sponsors) [![extension-for-VSCode](https://img.shields.io/badge/extension%20for-VSCode-blue.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-orange?style=flat-square)](https://github.com/actions-cool/issues-helper)
</div>
[![](https://cdn-images-1.medium.com/max/2000/1*NIlj0-TdLMbo_hzSBP8tmg.png)](https://www.antdv.com/)
[English](./README.md) | 简体中文
[README in English](README.md)
## 特性
- 提炼自企业级中后台产品的交互语言和视觉风格。
- 开箱即用的高质量 Vue 组件。
- 共享 [Ant Design of React](http://ant-design.gitee.io/docs/spec/introduce-cn) 设计工具体系。
## 关注我们
收藏加关注,第一时间获取更新动态!
![star us](https://user-images.githubusercontent.com/6937879/261937060-e0501ab3-9388-4712-a25d-3f2ba2271865.gif)
## 支持环境
- 现代浏览器。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性)
- 支持服务端渲染。
- [Electron](https://electronjs.org/)
- 支持 Vue 2 和 Vue 3
| [<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 |
| --- | --- | --- | --- | --- | --- |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
- 共享[Ant Design of React](http://ant-design.gitee.io/docs/spec/introduce-cn)设计工具体系。
## 安装
### 使用 npm 或 yarn 安装
```bash
$ npm install ant-design-vue --save
$ npm install vue-antd-ui --save
```
```bash
$ yarn add ant-design-vue
$ yarn add vue-antd-ui
```
如果你的网络环境不佳,推荐使用 [cnpm](https://github.com/cnpm/cnpm)。
## 链接
- [首页](https://www.antdv.com/)
- [Vue 官方文档](https://cn.vuejs.org/)
- [Ant Design Of React](http://ant.design/)
- [首页](https://vuecomponent.github.io/ant-design/)
- [Vue官方文档](https://cn.vuejs.org/)
- [Antd React](http://ant.design/)
## 生态
| Project | Description |
| --- | --- |
| [vue-ref](https://github.com/vueComponent/vue-ref) | 您可以使用回调来获取组件的引用,类似 react |
| [ant-design-vue-helper](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) | ant-design-vue 的 vscode 扩展 |
| [vue-cli-plugin-ant-design](https://github.com/vueComponent/vue-cli-plugin-ant-design) | 使用 vue-cli3 快速使用 ant-design-vue 组件库 |
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | 在 DOM 模板中,您可以使用 ant-design-vue 组件的自定义事件camelCase |
| [@formily/antdv](https://github.com/formilyjs/antdv) | 这是一个结合了 Formily 和 ant-design-vue 的组件库 |
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | ant-design-vue 的 nuxt 模块扩展 |
| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | 基于 Ant Design X 设计规范的 Vue AI 界面解决方案 |
## 问答
> 强烈推荐阅读 [《提问的智慧》](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),更好的问题更容易获得帮助。
[![Let's fund issues in this repository](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/104172832)
## 赞助
ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续的发展,我们期望获得更多的[支持者](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md),你可以通过如下任何一种方式支持我们:
- [Patreon](https://www.patreon.com/tangjinzhou)
- [opencollective](https://opencollective.com/ant-design-vue)
- [paypal](https://www.paypal.me/tangjinzhou)
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
## 赞助商
成为赞助商,并在 Github 上的自述文件上获得您的徽标,并链接到您的网站。 [[成为赞助商](https://opencollective.com/ant-design-vue#sponsor)]
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
## 支持者
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://opencollective.com/ant-design-vue#backer)]
<a href="https://github.com/chuzhixin/vue-admin-beautiful" target="_blank"><img width="64" style="border-radius: 50%;" src="https://gitee.com/chu1204505056/image/raw/master/vue-admin-beautiful.png" title="vue-admin-beautiful"></a> <a href="https://opencollective.com/ant-design-vue/backer/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/10/avatar.svg"></a>
## Patreon
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://www.patreon.com/tangjinzhou)]
<a href="https://www.mokeyjay.com" target="_blank"><img width="64" style="border-radius: 50%;" src="https://www.mokeyjay.com/headimg.png" title="donation by Patreon"></a>
## [更多赞助者 (通过 Patreon、支付宝、微信、paypal 等等)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
## 贡献者
感谢所有为 ant-design-vue 做出贡献的人!
<a href="https://github.com/vueComponent/ant-design-vue/graphs/contributors">
<img src="https://contrib.rocks/image?repo=vueComponent/ant-design-vue&max=100&columns=15" />
</a>

View File

@ -1,106 +1,46 @@
<p align="center">
<a href="https://www.antdv.com/">
<img width="200" src="https://aliyuncdn.antdv.com/logo.png">
<a href="https://vuecomponent.github.io/ant-design/">
<img width="230" src="https://raw.githubusercontent.com/vueComponent/ant-design/master/logo.png">
</a>
</p>
<h1 align="center">
<a href="https://www.antdv.com/" target="_blank">Ant Design Vue</a>
</h1>
# [Ant Design Vue](https://vuecomponent.github.io/ant-design/)
[![Travis branch](https://api.travis-ci.org/vueComponent/ant-design.svg?branch=master)](https://travis-ci.org/vueComponent/ant-design)
[![Dependency Status](https://beta.gemnasium.com/badges/github.com/vueComponent/ant-design.svg)](https://beta.gemnasium.com/projects/github.com/vueComponent/ant-design)
[![npm package](https://img.shields.io/npm/v/vue-antd-ui.svg?style=flat)](https://www.npmjs.org/package/vue-antd-ui)
[![NPM downloads](http://img.shields.io/npm/dm/vue-antd-ui.svg?style=flat)](http://www.npmtrends.com/vue-antd-ui)
<div align="center">
An enterprise-class UI components based on Ant Design and Vue.
![test](https://github.com/vueComponent/ant-design-vue/workflows/test/badge.svg) [![codecov](https://img.shields.io/codecov/c/github/vueComponent/ant-design-vue/master.svg?style=flat-square)](https://codecov.io/gh/vueComponent/ant-design-vue) [![npm package](https://img.shields.io/npm/v/ant-design-vue.svg?style=flat-square)](https://www.npmjs.org/package/ant-design-vue) [![NPM downloads](http://img.shields.io/npm/dm/ant-design-vue.svg?style=flat-square)](http://www.npmtrends.com/ant-design-vue) [![backers](https://opencollective.com/ant-design-vue/backers/badge.svg)](#backers) [![sponsors](https://opencollective.com/ant-design-vue/sponsors/badge.svg)](#sponsors) [![extension-for-VSCode](https://img.shields.io/badge/extension%20for-VSCode-blue.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-orange?style=flat-square)](https://github.com/actions-cool/issues-helper)
An enterprise-class UI components based on Ant Design 3.X and Vue.
</div>
[![](https://cdn-images-1.medium.com/max/2000/1*NIlj0-TdLMbo_hzSBP8tmg.png)](https://www.antdv.com/)
English | [简体中文](./README-zh_CN.md)
[中文 README](README-zh_CN.md)
## Features
- An enterprise-class UI design system for desktop applications.
- A set of high-quality Vue components out of the box.
- A set of high-quality React components out of the box.
- Shared [Ant Design of React](https://ant.design/docs/spec/introduce) design resources.
## Getting started & staying tuned with us.
Star us, and you will receive all releases notifications from GitHub without any delay!
![star us](https://user-images.githubusercontent.com/6937879/261937060-e0501ab3-9388-4712-a25d-3f2ba2271865.gif)
## Environment Support
- Modern browsers. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#compatibility))
- Server-side Rendering
- Support Vue 2 & Vue 3
- [Electron](https://electronjs.org/)
| [<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 |
| --- | --- | --- | --- | --- | --- |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## Using npm or yarn
**We recommend using npm or yarn to install**, it not only makes development easier, but also allow you to take advantage of the rich ecosystem of Javascript packages and tooling.
**We recommend using npm or yarn to install**it not only makes development easierbut also allow you to take advantage of the rich ecosystem of Javascript packages and tooling.
```bash
$ npm install ant-design-vue --save
$ npm install vue-antd-ui --save
```
```bash
$ yarn add ant-design-vue
$ yarn add vue-antd-ui
```
If you are in a bad network environment, you can try other registries and tools like [cnpm](https://github.com/cnpm/cnpm).
If you are in a bad network environmentyou can try other registries and tools like [cnpm](https://github.com/cnpm/cnpm).
## Links
- [Home page](https://www.antdv.com/)
- [Home page](https://vuecomponent.github.io/ant-design/)
- [Vue](https://vuejs.org/)
- [Ant Design Of React](http://ant.design/)
- [Ant Design React](http://ant.design/)
## Ecosystem
| Project | Description |
| --- | --- |
| [vue-ref](https://github.com/vueComponent/vue-ref) | You can use the callback to get a reference like react |
| [ant-design-vue-helper](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) | A vscode extension for ant-design-vue |
| [vue-cli-plugin-ant-design](https://github.com/vueComponent/vue-cli-plugin-ant-design) | Vue-cli 3 plugin to add ant-design-vue |
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | The library function, implemented in the DOM template, can use the custom event of the ant-design-vue component (camelCase) |
| [@formily/antdv](https://github.com/formilyjs/antdv) | The Library with Formily and ant-design-vue |
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | A nuxt module for ant-design-vue |
| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | A Vue AI interface solutions base on the Ant Design X design specification |
## Donation
ant-design-vue is an MIT-licensed open source project. In order to achieve better and sustainable development of the project, we expect to gain more [backers](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md). You can support us in any of the following ways:
- [Patreon](https://www.patreon.com/tangjinzhou)
- [opencollective](https://opencollective.com/ant-design-vue)
- [paypal](https://www.paypal.me/tangjinzhou)
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
## Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ant-design-vue#sponsor)]
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
## [More Sponsor (From Patreon、alipay、wechat、paypal...)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
## Contributors
Thank you to all the people who already contributed to ant-design-vue!
<a href="https://github.com/vueComponent/ant-design-vue/graphs/contributors">
<img src="https://contrib.rocks/image?repo=vueComponent/ant-design-vue&max=100&columns=15" />
</a>
[![Let's fund issues in this repository](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/104172832)
This project is tested with BrowserStack.

View File

@ -1,17 +0,0 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 1.x | :white_check_mark: |
| 2.x | :x: |
| 3.x | :white_check_mark: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a reported vulnerability, what to expect if the vulnerability is accepted or declined, etc.

View File

@ -1,68 +0,0 @@
// Read all the api from current documents
const glob = require('glob');
const fs = require('fs');
const COMPONENT_NAME = /components\/([^/]*)/;
const PROP_NAME = /^\s*\|\s*([^\s|]*)/;
const components = {};
function mappingPropLine(component, line) {
const propMatch = line.match(PROP_NAME);
if (!propMatch) return;
const propName = propMatch[1];
if (!/^[a-z]/.test(propName)) return;
components[component] = Array.from(new Set([...(components[component] || []), propName]));
}
function apiReport(entities) {
const apis = {};
Object.keys(entities).forEach(component => {
const apiList = entities[component];
apiList.forEach(api => {
if (typeof apis[api] === 'function') {
apis[api] = [];
}
apis[api] = [...(apis[api] || []), component];
});
});
return apis;
}
function printReport(apis) {
const apiList = Object.keys(apis).map(api => ({
name: api,
componentList: apis[api],
}));
apiList.sort((a, b) => b.componentList.length - a.componentList.length);
// eslint-disable-next-line no-console
console.log('| name | components | comments |');
// eslint-disable-next-line no-console
console.log('| ---- | ---------- | -------- |');
apiList.forEach(({ name, componentList }) => {
// eslint-disable-next-line no-console
console.log('|', name, '|', componentList.join(', '), '| |');
});
}
module.exports = () => {
glob('components/*/*.md', (error, files) => {
files.forEach(filePath => {
// Read md file to parse content
const content = fs.readFileSync(filePath, 'utf8');
const component = filePath.match(COMPONENT_NAME)[1];
// Parse lines to get API
const lines = content.split(/[\r\n]+/);
lines.forEach(line => {
mappingPropLine(component, line);
});
});
printReport(apiReport(components));
});
};

View File

@ -1,27 +1,27 @@
#!/usr/bin/env node
'use strict';
'use strict'
require('colorful').colorful();
require('colorful').colorful()
const program = require('commander');
const packageInfo = require('../../package.json');
const program = require('commander')
const packageInfo = require('../../package.json')
program
.version(packageInfo.version)
.command('run [name]', 'run specified task')
.parse(process.argv);
.parse(process.argv)
// https://github.com/tj/commander.js/pull/260
const proc = program.runningCommand;
const proc = program.runningCommand
if (proc) {
proc.on('close', process.exit.bind(process));
proc.on('close', process.exit.bind(process))
proc.on('error', () => {
process.exit(1);
});
process.exit(1)
})
}
const subCmd = program.args[0];
const subCmd = program.args[0]
if (!subCmd || subCmd !== 'run') {
program.help();
program.help()
}

View File

@ -1,51 +1,26 @@
#!/usr/bin/env node
/* eslint-disable no-console */
'use strict';
'use strict'
require('colorful').colorful();
const gulp = require('gulp');
const program = require('commander');
program.option('-c --npm-tag <type>', 'add --npm-tag=xxx');
require('colorful').colorful()
const gulp = require('gulp')
const program = require('commander')
program.on('--help', () => {
console.log(' Usage:'.to.bold.blue.color);
console.log();
});
console.log(' Usage:'.to.bold.blue.color)
console.log()
})
program.parse(process.argv);
program.parse(process.argv)
function runTask(toRun) {
const metadata = { task: toRun };
// Gulp >= 4.0.0 (doesn't support events)
const taskInstance = gulp.task(toRun);
if (taskInstance === undefined) {
gulp.emit('task_not_found', metadata);
return;
}
const start = process.hrtime();
gulp.emit('task_start', metadata);
try {
taskInstance.apply(gulp);
metadata.hrDuration = process.hrtime(start);
gulp.emit('task_stop', metadata);
gulp.emit('stop');
} catch (err) {
err.hrDuration = process.hrtime(start);
err.task = metadata.task;
gulp.emit('task_err', err);
}
}
const task = program.args[0];
const task = program.args[0]
if (!task) {
program.help();
program.help()
} else {
console.log('antd-tools run', task);
console.log('antd-tools run', task)
require('../gulpfile');
require('../gulpfile')
runTask(task);
gulp.start(task)
}

View File

@ -1 +0,0 @@
fork github.com/youzan/vant packages/generator-types

View File

@ -1,23 +0,0 @@
const path = require('path');
const pkg = require('../../package.json');
const { parseAndWrite } = require('./lib/index.js');
const rootPath = path.resolve(__dirname, '../../');
parseAndWrite({
version: pkg.version,
name: 'ant-design-vue',
path: path.resolve(rootPath, './components'),
typingsPath: path.resolve(rootPath, './typings/global.d.ts'),
// default match lang
test: /en-US\.md/,
outputDir: path.resolve(rootPath, './vetur'),
tagPrefix: 'a-',
})
.then(result => {
// eslint-disable-next-line no-console
console.log(`generator types success: ${result} tags generated`);
})
.catch(error => {
console.error('generator types error', error);
return Promise.reject(error);
});

View File

@ -1,128 +0,0 @@
import type { Articals } from './parser';
import { formatType, removeVersion, toKebabCase } from './utils';
import type { VueTag } from './type';
function getComponentName(name: string, tagPrefix: string) {
if (name) {
return tagPrefix + toKebabCase(name.split(' ')[0]);
}
return '';
}
function parserProps(tag: VueTag, line: any) {
const [name, desc, type, defaultVal] = line;
if (
type &&
(type.includes('v-slot') ||
type.includes('slot') ||
type.includes('slots') ||
type.includes('slot-scoped'))
) {
tag.slots!.push({
name: removeVersion(name),
description: desc,
});
}
tag.attributes!.push({
name: removeVersion(name),
default: defaultVal,
description: desc,
value: {
type: formatType(type || ''),
kind: 'expression',
},
});
}
export function formatter(
articals: Articals,
componentName: string,
kebabComponentName: string,
tagPrefix = '',
) {
if (!articals.length) {
return;
}
const tags: VueTag[] = [];
const tag: VueTag = {
name: kebabComponentName,
slots: [],
events: [],
attributes: [],
};
tags.push(tag);
const tables = articals.filter(artical => artical.type === 'table');
tables.forEach(item => {
const { table } = item;
const prevIndex = articals.indexOf(item) - 1;
const prevArtical = articals[prevIndex];
if (!prevArtical || !prevArtical.content || !table || !table.body) {
return;
}
const tableTitle = prevArtical.content;
if (tableTitle.includes('API')) {
table.body.forEach(line => {
parserProps(tag, line);
});
return;
}
if (tableTitle.includes('events') && !tableTitle.includes(componentName)) {
table.body.forEach(line => {
const [name, desc] = line;
tag.events!.push({
name: removeVersion(name),
description: desc,
});
});
return;
}
// 额外的子组件
if (
tableTitle.includes(componentName) &&
!tableTitle.includes('events') &&
!tableTitle.includes('()')
) {
const childTag: VueTag = {
name: getComponentName(tableTitle.replace(/\.|\//g, ''), tagPrefix),
slots: [],
events: [],
attributes: [],
};
table.body.forEach(line => {
parserProps(childTag, line);
});
tags.push(childTag);
return;
}
// 额外的子组件事件
if (tableTitle.includes(componentName) && tableTitle.includes('events')) {
const childTagName = getComponentName(
tableTitle.replace('.', '').replace('events', ''),
tagPrefix,
);
const childTag: VueTag | undefined = tags.find(item => item.name === childTagName.trim());
if (!childTag) {
return;
}
table.body.forEach(line => {
const [name, desc] = line;
childTag.events!.push({
name: removeVersion(name),
description: desc,
});
});
return;
}
});
return tags;
}

View File

@ -1,84 +0,0 @@
import glob from 'fast-glob';
import { dirname, join } from 'path';
import { mdParser } from './parser';
import { formatter } from './formatter';
import { genWebTypes } from './web-types';
import { outputFileSync, readFileSync } from 'fs-extra';
import type { Options, VueTag } from './type';
import { getComponentName, normalizePath, toKebabCase } from './utils';
import { flatMap } from 'lodash';
async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
const mdPaths = await glob(normalizePath(`${options.path}/**/*.md`));
const data = mdPaths
.filter(md => options.test.test(md))
.map(path => {
const docPath = dirname(path);
const kebabComponentName =
options.tagPrefix + docPath.substring(docPath.lastIndexOf('/') + 1) || '';
const componentName = getComponentName(docPath.substring(docPath.lastIndexOf('/') + 1) || '');
const fileContent = readFileSync(path, 'utf-8');
return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix);
})
.filter(item => item) as VueTag[][];
const tags = new Map<String, VueTag>();
flatMap(data, item => item).forEach(mergedTag => mergeTag(tags, mergedTag));
return tags;
}
function readTypings(options: Options): Map<String, VueTag> {
const tags = new Map<String, VueTag>();
const fileContent = readFileSync(options.typingsPath, 'utf-8');
fileContent
.split('\n')
.filter(line => line && line.includes('typeof'))
.map(line => {
const l = line.trim();
return toKebabCase(l.substring(0, l.indexOf(':')));
})
.forEach(tagName =>
tags.set(tagName, {
name: tagName,
slots: [],
events: [],
attributes: [],
}),
);
return tags;
}
function mergeTag(tags: Map<String, VueTag>, mergedTag: VueTag) {
const tagName = mergedTag.name;
const vueTag = tags.get(tagName);
if (vueTag) {
vueTag.slots = [...vueTag.slots, ...mergedTag.slots];
vueTag.events = [...vueTag.events, ...mergedTag.events];
vueTag.attributes = [...vueTag.attributes, ...mergedTag.attributes];
} else {
tags.set(tagName, mergedTag);
}
}
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()];
const tags = new Map<String, VueTag>();
if (mergedTagsArr.length === 0) return [];
mergedTagsArr.forEach(mergedTags => {
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
});
return [...tags.values()];
}
export async function parseAndWrite(options: Options): Promise<Number> {
if (!options.outputDir) {
throw new Error('outputDir can not be empty.');
}
const tagsFromMarkdown = await readMarkdown(options);
const tagsFromTypings = await readTypings(options);
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
const webTypes = genWebTypes(tags, options);
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
return tags.length;
}
export default { parseAndWrite };

View File

@ -1,107 +0,0 @@
/* eslint-disable no-cond-assign */
const TITLE_REG = /^(#+)\s+([^\n]*)/;
const TABLE_REG = /^\|.+\r?\n\|\s*-+/;
const TD_REG = /\s*`[^`]+`\s*|([^|`]+)/g;
const TABLE_SPLIT_LINE_REG = /^\|\s*-/;
type TableContent = {
head: string[];
body: string[][];
};
export type Artical = {
type: string;
content?: string;
table?: TableContent;
level?: number;
};
export type Articals = Artical[];
function readLine(input: string) {
const end = input.indexOf('\n');
return input.substring(0, end !== -1 ? end : input.length);
}
function splitTableLine(line: string) {
line = line.replace(/\\\|/g, 'JOIN');
const items = line.split('|').map(item => item.trim().replace(/JOIN/g, '|'));
// remove pipe character on both sides
items.pop();
items.shift();
return items;
}
function tableParse(input: string) {
let start = 0;
let isHead = true;
const end = input.length;
const table: TableContent = {
head: [],
body: [],
};
while (start < end) {
const target = input.substring(start);
const line = readLine(target);
if (!/^\|/.test(target)) {
break;
}
if (TABLE_SPLIT_LINE_REG.test(target)) {
isHead = false;
} else if (!isHead && line.includes('|')) {
const matched = line.trim().match(TD_REG);
if (matched) {
table.body.push(splitTableLine(line));
}
}
start += line.length + 1;
}
return {
table,
usedLength: start,
};
}
export function mdParser(input: string): Articals {
const artical = [];
let start = 0;
const end = input.length;
while (start < end) {
const target = input.substring(start);
let match;
if ((match = TITLE_REG.exec(target))) {
artical.push({
type: 'title',
content: match[2].replace('\r', ''),
level: match[1].length,
});
start += match.index + match[0].length;
} else if ((match = TABLE_REG.exec(target))) {
const { table, usedLength } = tableParse(target.substring(match.index));
artical.push({
type: 'table',
table,
});
start += match.index + usedLength;
} else {
start += readLine(target).length + 1;
}
}
return artical;
}

View File

@ -1,45 +0,0 @@
import type { PathLike } from 'fs';
export type VueSlot = {
name: string;
description: string;
};
export type VueEventArgument = {
name: string;
type: string;
};
export type VueEvent = {
name: string;
description?: string;
arguments?: VueEventArgument[];
};
export type VueAttribute = {
name: string;
default: string;
description: string;
value: {
kind: 'expression';
type: string;
};
};
export type VueTag = {
name: string;
slots: VueSlot[];
events: VueEvent[];
attributes: VueAttribute[];
description?: string;
};
export type Options = {
name: string;
path: PathLike;
typingsPath: PathLike;
test: RegExp;
version: string;
outputDir?: string;
tagPrefix?: string;
};

View File

@ -1,30 +0,0 @@
// myName -> my-name
export function toKebabCase(camel: string): string {
return camel.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase();
}
// name `v2.0.0` -> name
export function removeVersion(str: string) {
return str.replace(/`(\w|\.)+`/g, '').trim();
}
// *boolean* -> boolean
// _boolean_ -> boolean
export function formatType(type: string) {
return type
.replace(/(^(\*|_))|((\*|_)$)/g, '')
.replace('\\', '')
.replace('\\', '');
}
export function getComponentName(name: string) {
const title = name
.split('-')
.map(it => it.substring(0, 1) + it.substring(1))
.join('');
return title.substring(0, 1).toUpperCase() + title.substring(1);
}
export function normalizePath(path: string): string {
return path.replace(/\\/g, '/');
}

View File

@ -1,18 +0,0 @@
import type { VueTag, Options } from './type';
// create web-types.json to provide autocomplete in JetBrains IDEs
export function genWebTypes(tags: VueTag[], options: Options) {
return {
$schema: 'https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json',
framework: 'vue',
name: options.name,
version: options.version,
contributions: {
html: {
tags,
attributes: [],
'types-syntax': 'typescript',
},
},
};
}

View File

@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "ES2017",
"outDir": "./lib",
"module": "commonjs",
"strict": true,
"declaration": true,
"skipLibCheck": true,
"esModuleInterop": true,
"lib": ["esnext"]
},
"include": ["src/**/*"]
}

View File

@ -1,57 +1,32 @@
const { resolve, isThereHaveBrowserslistConfig } = require('./utils/projectHelper');
'use strict'
module.exports = function (modules) {
const plugins = [
[
resolve('@babel/plugin-transform-typescript'),
{
isTSX: true,
},
],
[resolve('@vue/babel-plugin-jsx'), { mergeProps: false, enableObjectSlots: false }],
resolve('@babel/plugin-proposal-optional-chaining'),
resolve('@babel/plugin-transform-object-assign'),
resolve('@babel/plugin-proposal-object-rest-spread'),
resolve('@babel/plugin-proposal-export-default-from'),
resolve('@babel/plugin-proposal-export-namespace-from'),
resolve('@babel/plugin-proposal-class-properties'),
resolve('@babel/plugin-syntax-dynamic-import'),
[
resolve('@babel/plugin-transform-runtime'),
{
useESModules: modules === false,
version:
require(`${process.cwd()}/package.json`).dependencies['@babel/runtime'] || '^7.10.4',
},
],
// resolve('babel-plugin-inline-import-data-uri'),
// resolve('@babel/plugin-transform-member-expression-literals'),
// resolve('@babel/plugin-transform-property-literals'),
// resolve('@babel/plugin-proposal-export-default-from'),
// resolve('@babel/plugin-transform-object-assign'),
// resolve('@babel/plugin-transform-template-literals'),
// resolve('@babel/plugin-proposal-object-rest-spread'),
// resolve('@babel/plugin-proposal-class-properties'),
];
require.resolve('babel-plugin-transform-vue-jsx'),
require.resolve('babel-plugin-transform-es3-member-expression-literals'),
require.resolve('babel-plugin-transform-es3-property-literals'),
require.resolve('babel-plugin-transform-object-assign'),
require.resolve('babel-plugin-transform-object-rest-spread'),
]
plugins.push([require.resolve('babel-plugin-transform-runtime'), {
polyfill: false,
}])
return {
presets: [
[
resolve('@babel/preset-env'),
{
modules,
targets: isThereHaveBrowserslistConfig()
? undefined
: {
browsers: ['last 2 versions', 'Firefox ESR', '> 1%', 'ie >= 11'],
},
[require.resolve('babel-preset-env'), {
modules,
targets: {
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4',
],
},
],
}],
],
plugins,
env: {
test: {
plugins: [resolve('babel-plugin-istanbul')],
},
},
};
};
}
}

View File

@ -1,17 +0,0 @@
'use strict';
const runCmd = require('./runCmd');
module.exports = function (done) {
if (process.env.NPM_CLI) {
done(process.env.NPM_CLI);
return;
}
runCmd('which', ['tnpm'], code => {
let npm = 'npm';
if (!code) {
npm = 'tnpm';
}
done(npm);
});
};

View File

@ -1,24 +0,0 @@
'use strict';
const fs = require('fs');
const { getProjectPath } = require('./utils/projectHelper');
module.exports = function () {
let my = {};
if (fs.existsSync(getProjectPath('tsconfig.json'))) {
my = require(getProjectPath('tsconfig.json'));
}
return Object.assign(
{
noUnusedParameters: true,
noUnusedLocals: true,
strictNullChecks: true,
target: 'es6',
jsx: 'preserve',
moduleResolution: 'node',
declaration: true,
allowSyntheticDefaultImports: true,
},
my.compilerOptions,
);
};

View File

@ -1,84 +1,68 @@
const { getProjectPath, resolve } = require('./utils/projectHelper');
const path = require('path');
const webpack = require('webpack');
const WebpackBar = require('webpackbar');
const { merge } = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const CleanUpStatsPlugin = require('./utils/CleanUpStatsPlugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const deepAssign = require('deep-assign')
const chalk = require('chalk')
const postcssConfig = require('./postcssConfig')
const distFileBaseName = 'antd'
module.exports = function (modules) {
const pkg = require(path.join(process.cwd(), 'package.json'))
const babelConfig = require('./getBabelCommonConfig')(modules || false)
const distFileBaseName = 'antd';
const pluginImportOptions = [
{
style: true,
libraryName: 'antd',
libraryDirectory: 'components',
},
]
const svgRegex = /\.svg(\?v=\d+\.\d+\.\d+)?$/;
const svgOptions = {
limit: 10000,
minetype: 'image/svg+xml',
};
// if (distFileBaseName !== 'antd') {
// pluginImportOptions.push({
// style: 'css',
// libraryDirectory: 'components',
// libraryName: 'antd',
// })
// }
const imageOptions = {
limit: 10000,
};
babelConfig.plugins.push([
require.resolve('babel-plugin-import'),
pluginImportOptions,
])
function getWebpackConfig(modules, esm = false) {
const pkg = require(getProjectPath('package.json'));
const babelConfig = require('./getBabelCommonConfig')(modules || false);
const pluginImportOptions = {
style: true,
libraryName: distFileBaseName,
libraryDirectory: 'components',
};
babelConfig.plugins.push([resolve('babel-plugin-import'), pluginImportOptions]);
if (modules === false) {
babelConfig.plugins.push(require.resolve('./replaceLib'));
}
/** @type {import('webpack').Configuration} */
const config = {
devtool: 'source-map',
output: {
path: getProjectPath('./dist/'),
path: path.join(process.cwd(), './dist/'),
filename: '[name].js',
},
resolve: {
modules: ['node_modules', path.join(__dirname, '../node_modules')],
extensions: [
'.web.tsx',
'.web.ts',
'.web.jsx',
'.web.js',
'.ts',
'.tsx',
'.js',
'.jsx',
'.vue',
'.md',
'.json',
],
extensions: ['.js', '.jsx', '.vue', '.md', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': process.cwd(),
},
fallback: [
'child_process',
'cluster',
'dgram',
'dns',
'fs',
'module',
'net',
'readline',
'repl',
'tls',
].reduce((acc, name) => Object.assign({}, acc, { [name]: 'empty' }), {}),
},
node: [
'child_process',
'cluster',
'dgram',
'dns',
'fs',
'module',
'net',
'readline',
'repl',
'tls',
].reduce((acc, name) => Object.assign({}, acc, { [name]: 'empty' }), {}),
module: {
noParse: [/moment.js/],
rules: [
{
test: /\.vue$/,
@ -89,19 +73,14 @@ function getWebpackConfig(modules, esm = false) {
options: {
loaders: {
js: [
{
loader: 'babel-loader',
{ loader: 'babel-loader',
options: {
presets: [resolve('@babel/preset-env')],
presets: ['env'],
plugins: [
[
resolve('@vue/babel-plugin-jsx'),
{ mergeProps: false, enableObjectSlots: false },
],
resolve('@babel/plugin-proposal-object-rest-spread'),
'transform-vue-jsx',
'transform-object-rest-spread',
],
},
},
}},
],
},
},
@ -110,164 +89,133 @@ function getWebpackConfig(modules, esm = false) {
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/,
loader: 'babel-loader', exclude: /node_modules/,
options: babelConfig,
},
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
options: babelConfig,
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer'],
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {
sourceMap: true,
},
sourceMap: true,
},
},
],
},
// Images
{
test: svgRegex,
loader: 'url-loader',
options: svgOptions,
{
loader: 'postcss-loader',
options: Object.assign(
{},
postcssConfig,
{ sourceMap: true }
),
},
],
}),
},
{
test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i,
loader: 'url-loader',
options: imageOptions,
test: /\.less$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: Object.assign(
{},
postcssConfig,
{ sourceMap: true }
),
},
{
loader: 'less-loader',
options: {
sourceMap: true,
},
},
],
}),
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new ExtractTextPlugin({
filename: '[name].css',
disable: false,
allChunks: true,
}),
new CaseSensitivePathsPlugin(),
new webpack.BannerPlugin(`
${pkg.name} v${pkg.version}
${distFileBaseName} v${pkg.version}
Copyright 2017-present, Ant Design Vue.
Copyright 2017-present, vue-antd-ui.
All rights reserved.
`),
new WebpackBar({
name: '🚚 Ant Design Vue Tools',
color: '#2f54eb',
new webpack.ProgressPlugin((percentage, msg, addInfo) => {
const stream = process.stderr
if (stream.isTTY && percentage < 0.71) {
stream.cursorTo(0)
stream.write(`📦 ${chalk.magenta(msg)} (${chalk.magenta(addInfo)})`)
stream.clearLine(1)
} else if (percentage === 1) {
console.log(chalk.green('\nwebpack: bundle build is now finished.'))
}
}),
new CleanUpStatsPlugin(),
],
performance: {
hints: false,
},
};
if (process.env.RUN_ENV === 'PRODUCTION') {
let entry = ['./index'];
config.externals = [
{
vue: {
root: 'Vue',
commonjs2: 'vue',
commonjs: 'vue',
amd: 'vue',
module: 'vue',
},
},
];
if (esm) {
entry = ['./index.esm'];
config.experiments = {
...config.experiments,
outputModule: true,
};
config.output.chunkFormat = 'module';
config.output.library = {
type: 'module',
};
config.target = 'es2019';
} else {
config.output.libraryTarget = 'umd';
config.output.library = distFileBaseName;
config.output.globalObject = 'this';
}
const entryName = esm ? `${distFileBaseName}.esm` : distFileBaseName;
config.optimization = {
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
warnings: false,
},
}),
],
};
// Development
const uncompressedConfig = merge({}, config, {
entry: {
[entryName]: entry,
},
mode: 'development',
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
});
// Production
const prodConfig = merge({}, config, {
entry: {
[`${entryName}.min`]: entry,
},
mode: 'production',
plugins: [
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
optimization: {
minimize: true,
minimizer: [new CssMinimizerPlugin({})],
},
});
return [prodConfig, uncompressedConfig];
}
return [config];
if (process.env.RUN_ENV === 'PRODUCTION') {
const entry = ['./index']
config.entry = {
[`${distFileBaseName}.min`]: entry,
}
config.externals = {
vue: {
root: 'Vue',
commonjs2: 'vue',
commonjs: 'vue',
amd: 'vue',
},
}
config.output.library = distFileBaseName
config.output.libraryTarget = 'umd'
const uncompressedConfig = deepAssign({}, config)
config.plugins = config.plugins.concat([
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
output: {
ascii_only: true,
},
compress: {
warnings: false,
},
}),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
}),
])
uncompressedConfig.entry = {
[distFileBaseName]: entry,
}
uncompressedConfig.plugins.push(new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
}))
return [config, uncompressedConfig]
}
return config
}
getWebpackConfig.webpack = webpack;
getWebpackConfig.svgRegex = svgRegex;
getWebpackConfig.svgOptions = svgOptions;
getWebpackConfig.imageOptions = imageOptions;
module.exports = getWebpackConfig;

View File

@ -1,74 +1,56 @@
/* eslint-disable no-console */
const { getProjectPath, getConfig } = require('./utils/projectHelper');
const runCmd = require('./runCmd');
const getBabelCommonConfig = require('./getBabelCommonConfig');
const merge2 = require('merge2');
const { execSync } = require('child_process');
const through2 = require('through2');
const webpack = require('webpack');
const babel = require('gulp-babel');
const argv = require('minimist')(process.argv.slice(2));
const { Octokit } = require('@octokit/rest');
'use strict'
// const install = require('./install')
// const runCmd = require('./runCmd')
const getBabelCommonConfig = require('./getBabelCommonConfig')
const merge2 = require('merge2')
// const { execSync } = require('child_process')
const through2 = require('through2')
const transformLess = require('./transformLess')
const webpack = require('webpack')
const babel = require('gulp-babel')
// const argv = require('minimist')(process.argv.slice(2))
// const GitHub = require('github')
// const packageJson = require(`${process.cwd()}/package.json`)
// const getNpm = require('./getNpm')
// const selfPackage = require('../package.json')
const chalk = require('chalk');
const getNpmArgs = require('./utils/get-npm-args');
const getChangelog = require('./utils/getChangelog');
const path = require('path');
// const chalk = require('chalk')
// const getNpmArgs = require('./utils/get-npm-args')
const path = require('path')
// const watch = require('gulp-watch')
const ts = require('gulp-typescript');
const gulp = require('gulp');
const fs = require('fs');
const rimraf = require('rimraf');
const stripCode = require('gulp-strip-code');
const compareVersions = require('compare-versions');
const getTSCommonConfig = require('./getTSCommonConfig');
const replaceLib = require('./replaceLib');
const sortApiTable = require('./sortApiTable');
const { glob } = require('glob');
const gulp = require('gulp')
// const fs = require('fs')
const rimraf = require('rimraf')
const replaceLib = require('./replaceLib')
const stripCode = require('gulp-strip-code')
const packageJson = require(getProjectPath('package.json'));
const tsDefaultReporter = ts.reporter.defaultReporter();
const cwd = process.cwd();
const libDir = getProjectPath('lib');
const esDir = getProjectPath('es');
const localeDir = getProjectPath('locale');
const cwd = process.cwd()
const libDir = path.join(cwd, 'lib')
const esDir = path.join(cwd, 'es')
const tsConfig = getTSCommonConfig();
// FIXME: hard code, not find typescript can modify the path resolution
const localeDts = `import type { Locale } from '../lib/locale-provider';
declare const localeValues: Locale;
export default localeValues;`;
function dist(done) {
rimraf.sync(path.join(cwd, 'dist'));
process.env.RUN_ENV = 'PRODUCTION';
const webpackConfig = require(getProjectPath('webpack.build.conf.js'));
function dist (done) {
rimraf.sync(path.join(cwd, 'dist'))
process.env.RUN_ENV = 'PRODUCTION'
const webpackConfig = require(path.join(cwd, 'webpack.build.config.js'))
webpack(webpackConfig, (err, stats) => {
if (err) {
console.error(err.stack || err);
console.error(err.stack || err)
if (err.details) {
console.error(err.details);
console.error(err.details)
}
return;
return
}
const info = stats.toJson();
const { dist: { finalize } = {}, bail } = getConfig();
const info = stats.toJson()
if (stats.hasErrors()) {
(info.errors || []).forEach(error => {
console.error(error);
});
// https://github.com/ant-design/ant-design/pull/31662
if (bail) {
process.exit(1);
}
console.error(info.errors)
}
if (stats.hasWarnings()) {
console.warn(info.warnings);
console.warn(info.warnings)
}
const buildInfo = stats.toString({
@ -79,421 +61,80 @@ function dist(done) {
chunkModules: false,
hash: false,
version: false,
});
console.log(buildInfo);
// Additional process of dist finalize
if (finalize) {
console.log('[Dist] Finalization...');
finalize();
}
done(0);
});
})
console.log(buildInfo)
done(0)
})
}
const tsFiles = ['**/*.ts', '**/*.tsx', '!node_modules/**/*.*', 'typings/**/*.d.ts'];
function compileTs(stream) {
return stream
.pipe(ts(tsConfig))
.js.pipe(
through2.obj(function (file, encoding, next) {
// console.log(file.path, file.base);
file.path = file.path.replace(/\.[jt]sx$/, '.js');
this.push(file);
next();
}),
)
.pipe(gulp.dest(process.cwd()));
}
gulp.task('tsc', () =>
compileTs(
gulp.src(tsFiles, {
base: cwd,
}),
),
);
gulp.task('clean', () => {
rimraf.sync(getProjectPath('_site'));
rimraf.sync(getProjectPath('_data'));
});
function babelify(js, modules) {
const babelConfig = getBabelCommonConfig(modules);
babelConfig.babelrc = false;
delete babelConfig.cacheDirectory;
function babelify (js, modules) {
const babelConfig = getBabelCommonConfig(modules)
delete babelConfig.cacheDirectory
if (modules === false) {
babelConfig.plugins.push(replaceLib);
babelConfig.plugins.push(replaceLib)
} else {
babelConfig.plugins.push(require.resolve('babel-plugin-add-module-exports'))
}
const stream = js.pipe(babel(babelConfig)).pipe(
through2.obj(function z(file, encoding, next) {
this.push(file.clone());
if (modules !== false) {
const content = file.contents.toString(encoding);
file.contents = Buffer.from(
content
.replace(/lodash-es/g, 'lodash')
.replace(/@ant-design\/icons-vue/g, '@ant-design/icons-vue/lib/icons'),
);
this.push(file);
let stream = js.pipe(babel(babelConfig))
.pipe(through2.obj(function z (file, encoding, next) {
this.push(file.clone())
if (file.path.match(/\/style\/index\.js/)) {
const content = file.contents.toString(encoding)
file.contents = Buffer.from(content
.replace(/\/style\/?'/g, '/style/css\'')
.replace(/\.less/g, '.css'))
file.path = file.path.replace(/index\.js/, 'css.js')
this.push(file)
next()
} else {
next()
}
next();
}),
);
return stream.pipe(gulp.dest(modules === false ? esDir : libDir));
}))
if (modules === false) {
stream = stream.pipe(stripCode({
start_comment: '@remove-on-es-build-begin',
end_comment: '@remove-on-es-build-end',
}))
}
return stream.pipe(gulp.dest(modules === false ? esDir : libDir))
}
function compile(modules) {
const { compile: { transformTSFile, transformFile } = {} } = getConfig();
rimraf.sync(modules !== false ? libDir : esDir);
function compile (modules) {
rimraf.sync(modules !== false ? libDir : esDir)
const less = gulp.src(['components/**/*.less'])
.pipe(through2.obj(function (file, encoding, next) {
this.push(file.clone())
if (file.path.match(/\/style\/index\.less$/) || file.path.match(/\/style\/v2-compatible-reset\.less$/)) {
transformLess(file.path).then((css) => {
file.contents = Buffer.from(css)
file.path = file.path.replace(/\.less$/, '.css')
this.push(file)
next()
}).catch((e) => {
console.error(e)
})
} else {
next()
}
}))
.pipe(gulp.dest(modules === false ? esDir : libDir))
const assets = gulp.src(['components/**/*.@(png|svg)']).pipe(gulp.dest(modules === false ? esDir : libDir))
const assets = gulp
.src(['components/**/*.@(png|svg)'])
.pipe(gulp.dest(modules === false ? esDir : libDir));
let error = 0;
// =============================== FILE ===============================
let transformFileStream;
if (transformFile) {
transformFileStream = gulp
.src(['components/**/*.tsx'])
.pipe(
through2.obj(function (file, encoding, next) {
let nextFile = transformFile(file) || file;
nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
nextFile.forEach(f => this.push(f));
next();
}),
)
.pipe(gulp.dest(modules === false ? esDir : libDir));
}
// ================================ TS ================================
const source = [
'components/**/*.js',
'components/**/*.jsx',
'components/**/*.tsx',
'components/**/*.ts',
'typings/**/*.d.ts',
'!components/*/__tests__/*',
];
// Strip content if needed
let sourceStream = gulp.src(source);
if (modules === false) {
sourceStream = sourceStream.pipe(
stripCode({
start_comment: '@remove-on-es-build-begin',
end_comment: '@remove-on-es-build-end',
}),
);
}
if (transformTSFile) {
sourceStream = sourceStream.pipe(
through2.obj(function (file, encoding, next) {
let nextFile = transformTSFile(file) || file;
nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
nextFile.forEach(f => this.push(f));
next();
}),
);
}
const tsResult = sourceStream.pipe(
ts(tsConfig, {
error(e) {
tsDefaultReporter.error(e);
error = 1;
},
finish: tsDefaultReporter.finish,
}),
);
function check() {
if (error && !argv['ignore-error']) {
process.exit(1);
}
}
tsResult.on('finish', check);
tsResult.on('end', check);
const tsFilesStream = babelify(tsResult.js, modules);
const tsd = tsResult.dts.pipe(gulp.dest(modules === false ? esDir : libDir));
return merge2([tsFilesStream, tsd, assets, transformFileStream].filter(s => s));
// '!components/vc-slider/**/*', // exclude vc-slider
]
const jsFilesStream = babelify(gulp.src(source), modules)
return merge2([less, jsFilesStream, assets])
}
function generateLocale() {
if (!fs.existsSync(localeDir)) {
fs.mkdirSync(localeDir);
}
const localeFiles = glob.sync('components/locale/*.ts?(x)');
localeFiles.forEach(item => {
const match = item.match(/components\/locale\/(.*)\.tsx?/);
if (match) {
const locale = match[1];
fs.writeFileSync(
path.join(localeDir, `${locale}.js`),
`module.exports = require('../lib/locale/${locale}');`,
);
fs.writeFileSync(path.join(localeDir, `${locale}.d.ts`), localeDts);
}
});
}
function tag() {
console.log('tagging');
const { version } = packageJson;
execSync(`git config --global user.email ${process.env.GITHUB_USER_EMAIL}`);
execSync(`git config --global user.name ${process.env.GITHUB_USER_NAME}`);
execSync(`git tag ${version}`);
execSync(
`git push https://${process.env.GITHUB_TOKEN}@github.com/vueComponent/ant-design-vue.git ${version}:${version}`,
);
execSync(
`git push https://${process.env.GITHUB_TOKEN}@github.com/vueComponent/ant-design-vue.git master:master`,
);
console.log('tagged');
}
function githubRelease(done) {
const changlogFiles = [
path.join(cwd, 'CHANGELOG.en-US.md'),
path.join(cwd, 'CHANGELOG.zh-CN.md'),
];
console.log('creating release on GitHub');
if (!process.env.GITHUB_TOKEN) {
console.log('no GitHub token found, skip');
return;
}
if (!changlogFiles.every(file => fs.existsSync(file))) {
console.log('no changelog found, skip');
return;
}
const github = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
const date = new Date();
const { version } = packageJson;
const enChangelog = getChangelog(changlogFiles[0], version);
const cnChangelog = getChangelog(changlogFiles[1], version);
const changelog = [
`\`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}\``,
enChangelog,
'\n',
'---',
'\n',
cnChangelog,
].join('\n');
const [_, owner, repo] = execSync('git remote get-url origin') // eslint-disable-line
.toString()
.match(/github.com[:/](.+)\/(.+)\.git/);
github.repos
.createRelease({
owner,
repo,
tag_name: version,
name: version,
body: changelog,
})
.then(() => {
done();
})
.catch(err => {
console.log(err);
});
}
gulp.task(
'tag',
gulp.series(done => {
tag();
githubRelease(done);
}),
);
gulp.task(
'check-git',
gulp.series(done => {
runCmd('git', ['status', '--porcelain'], (code, result) => {
if (/^\?\?/m.test(result)) {
return done(`There are untracked files in the working tree.\n${result}
`);
}
if (/^([ADRM]| [ADRM])/m.test(result)) {
return done(`There are uncommitted changes in the working tree.\n${result}
`);
}
return done();
});
}),
);
function publish(tagString, done) {
let args = ['publish', '--with-antd-tools'];
if (tagString) {
args = args.concat(['--tag', tagString]);
}
const publishNpm = process.env.PUBLISH_NPM_CLI || 'npm';
runCmd(publishNpm, args, code => {
tag();
githubRelease(() => {
done(code);
});
});
}
function pub(done) {
const notOk = !packageJson.version.match(/^\d+\.\d+\.\d+$/);
let tagString;
if (argv['npm-tag']) {
tagString = argv['npm-tag'];
}
if (!tagString && notOk) {
tagString = 'next';
}
if (packageJson.scripts['pre-publish']) {
runCmd('npm', ['run', 'pre-publish'], code2 => {
if (code2) {
done(code2);
return;
}
publish(tagString, done);
});
} else {
publish(tagString, done);
}
}
const startTime = new Date();
gulp.task('compile-with-es', done => {
console.log('start compile at ', startTime);
console.log('[Parallel] Compile to es...');
compile(false).on('finish', done);
});
gulp.task('compile-with-lib', done => {
console.log('[Parallel] Compile to js...');
compile().on('finish', () => {
generateLocale();
done();
});
});
gulp.task('compile-finalize', done => {
// Additional process of compile finalize
const { compile: { finalize } = {} } = getConfig();
if (finalize) {
console.log('[Compile] Finalization...');
finalize();
}
done();
});
gulp.task(
'compile',
gulp.series(gulp.parallel('compile-with-es', 'compile-with-lib'), 'compile-finalize', done => {
console.log('end compile at ', new Date());
console.log('compile time ', (new Date() - startTime) / 1000, 's');
done();
}),
);
gulp.task(
'dist',
gulp.series(done => {
dist(done);
}),
);
gulp.task(
'pub',
gulp.series('check-git', 'compile', 'dist', done => {
// if (!process.env.GITHUB_TOKEN) {
// console.log('no GitHub token found, skip');
// } else {
// pub(done);
// }
pub(done);
}),
);
gulp.task(
'pub-with-ci',
gulp.series(done => {
if (!process.env.NPM_TOKEN) {
console.log('no NPM token found, skip');
} else {
const github = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
const [_, owner, repo] = execSync('git remote get-url origin') // eslint-disable-line
.toString()
.match(/github.com[:/](.+)\/(.+)\.git/);
const getLatestRelease = github.repos.getLatestRelease({
owner,
repo,
});
const listCommits = github.repos.listCommits({
owner,
repo,
per_page: 1,
});
Promise.all([getLatestRelease, listCommits]).then(([latestRelease, commits]) => {
const preVersion = latestRelease.data.tag_name;
const { version } = packageJson;
const [_, newVersion] = commits.data[0].commit.message.trim().match(/bump (.+)/) || []; // eslint-disable-line
if (
compareVersions(version, preVersion) === 1 &&
newVersion &&
newVersion.trim() === version
) {
// eslint-disable-next-line no-unused-vars
runCmd('npm', ['run', 'pub'], _code => {
done();
});
} else {
console.log('donot need publish' + version);
}
});
}
}),
);
gulp.task(
'guard',
gulp.series(done => {
function reportError() {
console.log(chalk.bgRed('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'));
console.log(chalk.bgRed('!! `npm publish` is forbidden for this package. !!'));
console.log(chalk.bgRed('!! Use `npm run pub` instead. !!'));
console.log(chalk.bgRed('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'));
}
const npmArgs = getNpmArgs();
if (npmArgs) {
for (let arg = npmArgs.shift(); arg; arg = npmArgs.shift()) {
if (
/^pu(b(l(i(sh?)?)?)?)?$/.test(arg) &&
npmArgs.indexOf('--with-antd-tools') < 0 &&
!process.env.npm_config_with_antd_tools
) {
reportError();
done(1);
return;
}
}
}
done();
}),
);
gulp.task(
'sort-api-table',
gulp.series(done => {
sortApiTable();
done();
}),
);
gulp.task('dist', ['compile'], (done) => {
dist(done)
})
gulp.task('compile', ['compile-with-es'], () => {
compile()
})
gulp.task('compile-with-es', () => {
compile(false)
})

View File

@ -0,0 +1,18 @@
const rucksack = require('rucksack-css')
const autoprefixer = require('autoprefixer')
module.exports = {
plugins: [
rucksack(),
autoprefixer({
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4',
],
}),
],
}

View File

@ -1,39 +1,27 @@
'use strict';
'use strict'
const { dirname } = require('path');
const fs = require('fs');
const { getProjectPath } = require('./utils/projectHelper');
const { join, dirname } = require('path')
const fs = require('fs')
function replacePath(path) {
const cwd = process.cwd()
function replacePath (path) {
if (path.node.source && /\/lib\//.test(path.node.source.value)) {
const esModule = path.node.source.value.replace('/lib/', '/es/');
const esPath = dirname(getProjectPath('node_modules', esModule));
const esModule = path.node.source.value.replace('/lib/', '/es/')
const esPath = dirname(join(cwd, `node_modules/${esModule}`))
if (fs.existsSync(esPath)) {
path.node.source.value = esModule;
}
}
// @ant-design/icons-vue/xxx => @ant-design/icons-vue/es/icons/xxx
const antdIconMatcher = /@ant-design\/icons-vue\/([^/]*)$/;
if (path.node.source && antdIconMatcher.test(path.node.source.value)) {
const esModule = path.node.source.value.replace(
antdIconMatcher,
(_, iconName) => `@ant-design/icons-vue/es/icons/${iconName}`,
);
const esPath = dirname(getProjectPath('node_modules', esModule));
if (fs.existsSync(esPath)) {
path.node.source.value = esModule;
path.node.source.value = esModule
}
}
}
function replaceLib() {
function replaceLib () {
return {
visitor: {
ImportDeclaration: replacePath,
ExportNamedDeclaration: replacePath,
},
};
}
}
module.exports = replaceLib;
module.exports = replaceLib

View File

@ -1,28 +1,20 @@
'use strict';
'use strict'
const isWindows = require('is-windows');
const getRunCmdEnv = require('./utils/getRunCmdEnv');
function runCmd(cmd, _args, fn) {
const args = _args || [];
if (isWindows()) {
args.unshift(cmd);
args.unshift('/c');
cmd = process.env.ComSpec;
}
const getRunCmdEnv = require('./utils/getRunCmdEnv')
function runCmd (cmd, _args, fn) {
const args = _args || []
const runner = require('child_process').spawn(cmd, args, {
// keep color
stdio: 'inherit',
env: getRunCmdEnv(),
});
})
runner.on('close', code => {
runner.on('close', (code) => {
if (fn) {
fn(code);
fn(code)
}
});
})
}
module.exports = runCmd;
module.exports = runCmd

View File

@ -1,165 +0,0 @@
const program = require('commander');
const majo = require('majo');
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const unified = require('unified');
const parse = require('remark-parse');
const stringify = require('remark-stringify');
const yamlConfig = require('remark-yaml-config');
const frontmatter = require('remark-frontmatter');
let fileAPIs = {};
const remarkWithYaml = unified()
.use(parse)
.use(stringify, {
paddedTable: false,
listItemIndent: 1,
stringLength: () => 3,
})
.use(frontmatter)
.use(yamlConfig);
const stream = majo.majo();
function getCellValue(node) {
return node.children[0].children[0].value;
}
// from small to large
const sizeBreakPoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
const whiteMethodList = ['afterChange', 'beforeChange'];
const groups = {
isDynamic: val => /^on[A-Z]/.test(val) || whiteMethodList.indexOf(val) > -1,
isSize: val => sizeBreakPoints.indexOf(val) > -1,
};
function asciiSort(prev, next) {
if (prev > next) {
return 1;
}
if (prev < next) {
return -1;
}
return 0;
}
// follow the alphabet order
function alphabetSort(nodes) {
// use toLowerCase to keep `case insensitive`
return nodes.sort((...comparison) =>
asciiSort(...comparison.map(val => getCellValue(val).toLowerCase())),
);
}
function sizeSort(nodes) {
return nodes.sort((...comparison) =>
asciiSort(...comparison.map(val => sizeBreakPoints.indexOf(getCellValue(val).toLowerCase()))),
);
}
function sort(ast, filename) {
const nameMatch = filename.match(/^components\/([^/]*)\//);
const componentName = nameMatch[1];
fileAPIs[componentName] = fileAPIs[componentName] || {
static: new Set(),
size: new Set(),
dynamic: new Set(),
};
ast.children.forEach(child => {
const staticProps = [];
// prefix with `on`
const dynamicProps = [];
// one of ['xs', 'sm', 'md', 'lg', 'xl']
const sizeProps = [];
// find table markdown type
if (child.type === 'table') {
// slice will create new array, so sort can affect the original array.
// slice(1) cut down the thead
child.children.slice(1).forEach(node => {
const value = getCellValue(node);
if (groups.isDynamic(value)) {
dynamicProps.push(node);
fileAPIs[componentName].dynamic.add(value);
} else if (groups.isSize(value)) {
sizeProps.push(node);
fileAPIs[componentName].size.add(value);
} else {
staticProps.push(node);
fileAPIs[componentName].static.add(value);
}
});
// eslint-disable-next-line
child.children = [
child.children[0],
...alphabetSort(staticProps),
...sizeSort(sizeProps),
...alphabetSort(dynamicProps),
];
}
});
return ast;
}
function sortAPI(md, filename) {
return remarkWithYaml.stringify(sort(remarkWithYaml.parse(md), filename));
}
function sortMiddleware(ctx) {
Object.keys(ctx.files).forEach(filename => {
const content = ctx.fileContents(filename);
ctx.writeContents(filename, sortAPI(content, filename));
});
}
module.exports = () => {
fileAPIs = {};
program
.version('0.1.0')
.option(
'-f, --file [file]',
'Specify which file to be transformed',
// default value
'components/**/index.+(zh-CN|en-US).md',
)
.option('-o, --output [output]', 'Specify component api output path', '~component-api.json')
.parse(process.argv);
// Get the markdown file all need to be transformed
/* eslint-disable no-console */
stream
.source(program.file)
.use(sortMiddleware)
.dest('.')
.then(() => {
if (program.output) {
const data = {};
Object.keys(fileAPIs).forEach(componentName => {
data[componentName] = {
static: [...fileAPIs[componentName].static],
size: [...fileAPIs[componentName].size],
dynamic: [...fileAPIs[componentName].dynamic],
};
});
const reportPath = path.resolve(program.output);
fs.writeFileSync(reportPath, JSON.stringify(data, null, 2), 'utf8');
console.log(chalk.cyan(`API list file: ${reportPath}`));
}
})
.then(() => {
console.log(chalk.green(`sort ant-design-vue api successfully!`));
});
/* eslint-enable no-console */
};

View File

@ -0,0 +1,33 @@
const less = require('less')
const { readFileSync } = require('fs')
const path = require('path')
const postcss = require('postcss')
const NpmImportPlugin = require('less-plugin-npm-import')
const postcssConfig = require('./postcssConfig')
function transformLess (lessFile, config = {}) {
const { cwd = process.cwd() } = config
const resolvedLessFile = path.resolve(cwd, lessFile)
let data = readFileSync(resolvedLessFile, 'utf-8')
data = data.replace(/^\uFEFF/, '')
// Do less compile
const lessOpts = {
paths: [path.dirname(resolvedLessFile)],
filename: resolvedLessFile,
plugins: [
new NpmImportPlugin({ prefix: '~' }),
],
}
return less.render(data, lessOpts)
.then((result) => {
const source = result.css
return postcss(postcssConfig.plugins).process(source)
})
.then((r) => {
return r.css
})
}
module.exports = transformLess

View File

@ -1,38 +0,0 @@
// We should use `stats` props of webpack. But it not work in v4.
class CleanUpStatsPlugin {
constructor(option) {
this.option = {
MiniCSSExtractPlugin: true,
tsLoader: true,
...option,
};
}
shouldPickStatChild(child) {
const { MiniCSSExtractPlugin } = this.option;
if (MiniCSSExtractPlugin && child.name.includes('mini-css-extract-plugin')) return false;
return true;
}
shouldPickWarning(message) {
const { tsLoader } = this.option;
if (tsLoader && /export .* was not found in .*/.test(message)) {
return false;
}
return true;
}
apply(compiler) {
compiler.hooks.done.tap('CleanUpStatsPlugin', stats => {
const { children, warnings } = stats.compilation;
if (Array.isArray(children)) {
stats.compilation.children = children.filter(child => this.shouldPickStatChild(child));
}
if (Array.isArray(warnings)) {
stats.compilation.warnings = warnings.filter(message => this.shouldPickWarning(message));
}
});
}
}
module.exports = CleanUpStatsPlugin;

View File

@ -1,23 +1,18 @@
'use strict';
'use strict'
// NOTE: the following code was partially adopted from https://github.com/iarna/in-publish
module.exports = function getNpmArgs() {
// https://github.com/iarna/in-publish/pull/14
if (process.env.npm_command) {
return [process.env.npm_command];
}
let npmArgv = null;
module.exports = function getNpmArgs () {
let npmArgv = null
try {
npmArgv = JSON.parse(process.env.npm_config_argv);
npmArgv = JSON.parse(process.env.npm_config_argv)
} catch (err) {
return null;
return null
}
if (typeof npmArgv !== 'object' || !npmArgv.cooked || !Array.isArray(npmArgv.cooked)) {
return null;
return null
}
return npmArgv.cooked;
};
return npmArgv.cooked
}

View File

@ -1,23 +1,23 @@
const fs = require('fs');
const fs = require('fs')
module.exports = function getChangelog(file, version) {
const lines = fs.readFileSync(file).toString().split('\n');
const changeLog = [];
const startPattern = new RegExp(`^## ${version}`);
const stopPattern = /^## /; // 前一个版本
const skipPattern = /^`/; // 日期
let begin = false;
module.exports = function getChangelog (file, version) {
const lines = fs.readFileSync(file).toString().split('\n')
const changeLog = []
const startPattern = new RegExp(`^## ${version}`)
const stopPattern = /^## / // 前一个版本
const skipPattern = /^`/ // 日期
let begin = false
for (let i = 0; i < lines.length; i += 1) {
const line = lines[i];
const line = lines[i]
if (begin && stopPattern.test(line)) {
break;
break
}
if (begin && line && !skipPattern.test(line)) {
changeLog.push(line);
changeLog.push(line)
}
if (!begin) {
begin = startPattern.test(line);
begin = startPattern.test(line)
}
}
return changeLog.join('\n');
};
return changeLog.join('\n')
}

View File

@ -1,23 +1,14 @@
'use strict';
'use strict'
const path = require('path');
const isWindows = require('is-windows');
const path = require('path')
module.exports = function getRunCmdEnv() {
const env = {};
Object.keys(process.env).forEach(key => {
env[key] = process.env[key];
});
module.exports = function getRunCmdEnv () {
const env = {}
Object.keys(process.env).forEach((key) => {
env[key] = process.env[key]
})
// make sure `antd-tools/node_modules/.bin` in the PATH env
const nodeModulesBinDir = path.join(__dirname, '../../node_modules/.bin');
Object.entries(env)
.filter(v => v.slice(0, 1).pop().toLowerCase() === 'path')
.forEach(v => {
const key = v.slice(0, 1).pop();
env[key] = env[key]
? `${nodeModulesBinDir}${isWindows() ? ';' : ':'}${env[key]}`
: nodeModulesBinDir;
});
return env;
};
const nodeModulesBinDir = path.join(__dirname, '../../node_modules/.bin')
env.PATH = env.PATH ? `${nodeModulesBinDir}:${env.PATH}` : nodeModulesBinDir
return env
}

View File

@ -1,80 +0,0 @@
const fs = require('fs');
const path = require('path');
const cwd = process.cwd();
function getProjectPath(...filePath) {
return path.join(cwd, ...filePath);
}
function resolve(moduleName) {
return require.resolve(moduleName);
}
// We need hack the require to ensure use package module first
// For example, `typescript` is required by `gulp-typescript` but provided by `antd`
// we do not need for ant-design-vue
let injected = false;
function injectRequire() {
if (injected) return;
const Module = require('module');
const oriRequire = Module.prototype.require;
Module.prototype.require = function (...args) {
const moduleName = args[0];
try {
return oriRequire.apply(this, args);
} catch (err) {
const newArgs = [...args];
if (moduleName[0] !== '/') {
newArgs[0] = getProjectPath('node_modules', moduleName);
}
return oriRequire.apply(this, newArgs);
}
};
injected = true;
}
function getConfig() {
const configPath = getProjectPath('.antd-tools.config.js');
if (fs.existsSync(configPath)) {
return require(configPath);
}
return {};
}
/**
* 是否存在可用的browserslist config
* https://github.com/browserslist/browserslist#queries
* @returns
*/
function isThereHaveBrowserslistConfig() {
try {
const packageJson = require(getProjectPath('package.json'));
if (packageJson.browserslist) {
return true;
}
} catch (e) {
//
}
if (fs.existsSync(getProjectPath('.browserslistrc'))) {
return true;
}
if (fs.existsSync(getProjectPath('browserslist'))) {
return true;
}
// parent项目的配置支持需要再补充
// ROWSERSLIST ROWSERSLIST_ENV 变量的形式,需要再补充。
return false;
}
module.exports = {
getProjectPath,
resolve,
injectRequire,
getConfig,
isThereHaveBrowserslistConfig,
};

View File

@ -1,19 +0,0 @@
module.exports = {
env: {
test: {
presets: [['@babel/preset-env']],
plugins: [
['@vue/babel-plugin-jsx', { mergeProps: false, enableObjectSlots: false }],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-transform-object-assign',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-runtime',
'transform-require-context',
],
},
},
};

View File

@ -1,58 +0,0 @@
const __NULL__ = { notExist: true };
export function spyElementPrototypes(Element, properties) {
const propNames = Object.keys(properties);
const originDescriptors = {};
propNames.forEach(propName => {
const originDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, propName);
originDescriptors[propName] = originDescriptor || __NULL__;
const spyProp = properties[propName];
if (typeof spyProp === 'function') {
// If is a function
Element.prototype[propName] = function spyFunc(...args) {
return spyProp.call(this, originDescriptor, ...args);
};
} else {
// Otherwise tread as a property
Object.defineProperty(Element.prototype, propName, {
...spyProp,
set(value) {
if (spyProp.set) {
return spyProp.set.call(this, originDescriptor, value);
}
return originDescriptor.set(value);
},
get() {
if (spyProp.get) {
return spyProp.get.call(this, originDescriptor);
}
return originDescriptor.get();
},
});
}
});
return {
mockRestore() {
propNames.forEach(propName => {
const originDescriptor = originDescriptors[propName];
if (originDescriptor === __NULL__) {
delete Element.prototype[propName];
} else if (typeof originDescriptor === 'function') {
Element.prototype[propName] = originDescriptor;
} else {
Object.defineProperty(Element.prototype, propName, originDescriptor);
}
});
},
};
}
export function spyElementPrototype(Element, propName, property) {
return spyElementPrototypes(Element, {
[propName]: property,
});
}

View File

@ -1,123 +0,0 @@
import type { ExtractPropTypes, PropType } from 'vue';
import { shallowRef, onMounted, defineComponent, onBeforeUnmount } from 'vue';
import Button from '../button';
import type { ButtonProps } from '../button';
import type { LegacyButtonType } from '../button/buttonTypes';
import { convertLegacyProps } from '../button/buttonTypes';
import useDestroyed from './hooks/useDestroyed';
import { objectType } from './type';
import { findDOMNode } from './props-util';
const actionButtonProps = {
type: {
type: String as PropType<LegacyButtonType>,
},
actionFn: Function as PropType<(...args: any[]) => any | PromiseLike<any>>,
close: Function,
autofocus: Boolean,
prefixCls: String,
buttonProps: objectType<ButtonProps>(),
emitEvent: Boolean,
quitOnNullishReturnValue: Boolean,
};
export type ActionButtonProps = ExtractPropTypes<typeof actionButtonProps>;
function isThenable<T>(thing?: PromiseLike<T>): boolean {
return !!(thing && thing.then);
}
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'ActionButton',
props: actionButtonProps,
setup(props, { slots }) {
const clickedRef = shallowRef<boolean>(false);
const buttonRef = shallowRef();
const loading = shallowRef(false);
let timeoutId: any;
const isDestroyed = useDestroyed();
onMounted(() => {
if (props.autofocus) {
timeoutId = setTimeout(() => findDOMNode(buttonRef.value)?.focus?.());
}
});
onBeforeUnmount(() => {
clearTimeout(timeoutId);
});
const onInternalClose = (...args: any[]) => {
props.close?.(...args);
};
const handlePromiseOnOk = (returnValueOfOnOk?: PromiseLike<any>) => {
if (!isThenable(returnValueOfOnOk)) {
return;
}
loading.value = true;
returnValueOfOnOk!.then(
(...args: any[]) => {
if (!isDestroyed.value) {
loading.value = false;
}
onInternalClose(...args);
clickedRef.value = false;
},
(e: Error) => {
// See: https://github.com/ant-design/ant-design/issues/6183
if (!isDestroyed.value) {
loading.value = false;
}
clickedRef.value = false;
return Promise.reject(e);
},
);
};
const onClick = (e: MouseEvent) => {
const { actionFn } = props;
if (clickedRef.value) {
return;
}
clickedRef.value = true;
if (!actionFn) {
onInternalClose();
return;
}
let returnValueOfOnOk: PromiseLike<any>;
if (props.emitEvent) {
returnValueOfOnOk = actionFn(e);
if (props.quitOnNullishReturnValue && !isThenable(returnValueOfOnOk)) {
clickedRef.value = false;
onInternalClose(e);
return;
}
} else if (actionFn.length) {
returnValueOfOnOk = actionFn(props.close);
// https://github.com/ant-design/ant-design/issues/23358
clickedRef.value = false;
} else {
returnValueOfOnOk = actionFn();
if (!returnValueOfOnOk) {
onInternalClose();
return;
}
}
handlePromiseOnOk(returnValueOfOnOk);
};
return () => {
const { type, prefixCls, buttonProps } = props;
return (
<Button
{...convertLegacyProps(type)}
onClick={onClick}
loading={loading.value}
prefixCls={prefixCls}
{...buttonProps}
ref={buttonRef}
v-slots={slots}
></Button>
);
};
},
});

View File

@ -1,168 +0,0 @@
import type { PropType } from 'vue';
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
import PropTypes from './vue-types';
import type { BaseInputInnerExpose } from './BaseInputInner';
import BaseInputInner from './BaseInputInner';
import { styleObjectToString } from '../vc-util/Dom/css';
export interface BaseInputExpose {
focus: () => void;
blur: () => void;
input: HTMLInputElement | HTMLTextAreaElement | null;
setSelectionRange: (
start: number,
end: number,
direction?: 'forward' | 'backward' | 'none',
) => void;
select: () => void;
getSelectionStart: () => number | null;
getSelectionEnd: () => number | null;
getScrollTop: () => number | null;
setScrollTop: (scrollTop: number) => void;
}
const BaseInput = defineComponent({
compatConfig: { MODE: 3 },
inheritAttrs: false,
props: {
disabled: PropTypes.looseBool,
type: PropTypes.string,
value: PropTypes.any,
lazy: PropTypes.bool.def(true),
tag: {
type: String as PropType<'input' | 'textarea'>,
default: 'input',
},
size: PropTypes.string,
style: PropTypes.oneOfType([String, Object]),
class: PropTypes.string,
},
emits: [
'change',
'input',
'blur',
'keydown',
'focus',
'compositionstart',
'compositionend',
'keyup',
'paste',
'mousedown',
],
setup(props, { emit, attrs, expose }) {
const inputRef = shallowRef<BaseInputInnerExpose>(null);
const renderValue = ref();
const isComposing = ref(false);
watch(
[() => props.value, isComposing],
() => {
if (isComposing.value) return;
renderValue.value = props.value;
},
{ immediate: true },
);
const handleChange = (e: Event) => {
emit('change', e);
};
const onCompositionstart = (e: CompositionEvent) => {
isComposing.value = true;
(e.target as any).composing = true;
emit('compositionstart', e);
};
const onCompositionend = (e: CompositionEvent) => {
isComposing.value = false;
(e.target as any).composing = false;
emit('compositionend', e);
const event = document.createEvent('HTMLEvents');
event.initEvent('input', true, true);
e.target.dispatchEvent(event);
handleChange(e);
};
const handleInput = (e: Event) => {
if (isComposing.value && props.lazy) {
renderValue.value = (e.target as HTMLInputElement).value;
return;
}
emit('input', e);
};
const handleBlur = (e: Event) => {
emit('blur', e);
};
const handleFocus = (e: Event) => {
emit('focus', e);
};
const focus = () => {
if (inputRef.value) {
inputRef.value.focus();
}
};
const blur = () => {
if (inputRef.value) {
inputRef.value.blur();
}
};
const handleKeyDown = (e: KeyboardEvent) => {
emit('keydown', e);
};
const handleKeyUp = (e: KeyboardEvent) => {
emit('keyup', e);
};
const setSelectionRange = (
start: number,
end: number,
direction?: 'forward' | 'backward' | 'none',
) => {
inputRef.value?.setSelectionRange(start, end, direction);
};
const select = () => {
inputRef.value?.select();
};
expose({
focus,
blur,
input: computed(() => inputRef.value?.input),
setSelectionRange,
select,
getSelectionStart: () => inputRef.value?.getSelectionStart(),
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
getScrollTop: () => inputRef.value?.getScrollTop(),
});
const handleMousedown = (e: MouseEvent) => {
emit('mousedown', e);
};
const handlePaste = (e: ClipboardEvent) => {
emit('paste', e);
};
const styleString = computed(() => {
return props.style && typeof props.style !== 'string'
? styleObjectToString(props.style)
: props.style;
});
return () => {
const { style, lazy, ...restProps } = props;
return (
<BaseInputInner
{...restProps}
{...attrs}
style={styleString.value}
onInput={handleInput}
onChange={handleChange}
onBlur={handleBlur}
onFocus={handleFocus}
ref={inputRef}
value={renderValue.value}
onCompositionstart={onCompositionstart}
onCompositionend={onCompositionend}
onKeyup={handleKeyUp}
onKeydown={handleKeyDown}
onPaste={handlePaste}
onMousedown={handleMousedown}
/>
);
};
},
});
export default BaseInput;

View File

@ -1,96 +0,0 @@
import type { PropType } from 'vue';
import { defineComponent, shallowRef } from 'vue';
import PropTypes from './vue-types';
export interface BaseInputInnerExpose {
focus: () => void;
blur: () => void;
input: HTMLInputElement | HTMLTextAreaElement | null;
setSelectionRange: (
start: number,
end: number,
direction?: 'forward' | 'backward' | 'none',
) => void;
select: () => void;
getSelectionStart: () => number | null;
getSelectionEnd: () => number | null;
getScrollTop: () => number | null;
setScrollTop: (scrollTop: number) => void;
}
const BaseInputInner = defineComponent({
compatConfig: { MODE: 3 },
// inheritAttrs: false,
props: {
disabled: PropTypes.looseBool,
type: PropTypes.string,
value: PropTypes.any,
tag: {
type: String as PropType<'input' | 'textarea'>,
default: 'input',
},
size: PropTypes.string,
onChange: Function as PropType<(e: Event) => void>,
onInput: Function as PropType<(e: Event) => void>,
onBlur: Function as PropType<(e: Event) => void>,
onFocus: Function as PropType<(e: Event) => void>,
onKeydown: Function as PropType<(e: Event) => void>,
onCompositionstart: Function as PropType<(e: Event) => void>,
onCompositionend: Function as PropType<(e: Event) => void>,
onKeyup: Function as PropType<(e: Event) => void>,
onPaste: Function as PropType<(e: Event) => void>,
onMousedown: Function as PropType<(e: Event) => void>,
},
emits: [
'change',
'input',
'blur',
'keydown',
'focus',
'compositionstart',
'compositionend',
'keyup',
'paste',
'mousedown',
],
setup(props, { expose }) {
const inputRef = shallowRef(null);
const focus = () => {
if (inputRef.value) {
inputRef.value.focus();
}
};
const blur = () => {
if (inputRef.value) {
inputRef.value.blur();
}
};
const setSelectionRange = (
start: number,
end: number,
direction?: 'forward' | 'backward' | 'none',
) => {
inputRef.value?.setSelectionRange(start, end, direction);
};
const select = () => {
inputRef.value?.select();
};
expose({
focus,
blur,
input: inputRef,
setSelectionRange,
select,
getSelectionStart: () => inputRef.value?.selectionStart,
getSelectionEnd: () => inputRef.value?.selectionEnd,
getScrollTop: () => inputRef.value?.scrollTop,
});
return () => {
const { tag: Tag, value, ...restProps } = props;
return <Tag {...restProps} ref={inputRef} value={value} />;
};
},
});
export default BaseInputInner;

View File

@ -0,0 +1,22 @@
export default {
methods: {
setState (state, callback) {
Object.assign(this.$data, typeof state === 'function' ? state(this.$data) : state)
this.$nextTick(() => {
callback && callback()
})
},
__emit () { // 直接调用listeners底层组件不需要vueTool记录events
const args = [].slice.call(arguments, 0)
const filterEvent = []
const eventName = args[0]
if (args.length && this.$listeners[eventName]) {
if (filterEvent.includes(eventName)) {
this.$emit(eventName, ...args.slice(1))
} else {
this.$listeners[eventName](...args.slice(1))
}
}
},
},
}

View File

@ -1,45 +0,0 @@
import { nextTick } from 'vue';
import { getOptionProps } from './props-util';
export default {
methods: {
setState(state = {}, callback: () => any) {
let newState = typeof state === 'function' ? state(this.$data, this.$props) : state;
if (this.getDerivedStateFromProps) {
const s = this.getDerivedStateFromProps(getOptionProps(this), {
...this.$data,
...newState,
});
if (s === null) {
return;
} else {
newState = { ...newState, ...(s || {}) };
}
}
Object.assign(this.$data, newState);
if (this._.isMounted) {
this.$forceUpdate();
}
nextTick(() => {
callback && callback();
});
},
__emit() {
// 直接调用事件底层组件不需要vueTool记录events
// eslint-disable-next-line prefer-rest-params
const args = [].slice.call(arguments, 0);
let eventName = args[0];
eventName = `on${eventName[0].toUpperCase()}${eventName.substring(1)}`;
const event = this.$props[eventName] || this.$attrs[eventName];
if (args.length && event) {
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
event[i](...args.slice(1));
}
} else {
event(...args.slice(1));
}
}
},
},
};

View File

@ -0,0 +1,87 @@
import Vue from 'vue'
import PropTypes from './vue-types'
export default {
props: {
autoMount: PropTypes.bool.def(true),
autoDestroy: PropTypes.bool.def(true),
visible: PropTypes.bool,
forceRender: PropTypes.bool.def(false),
parent: PropTypes.any,
getComponent: PropTypes.func.isRequired,
getContainer: PropTypes.func.isRequired,
children: PropTypes.func.isRequired,
},
mounted () {
if (this.autoMount) {
this.renderComponent()
}
},
updated () {
if (this.autoMount) {
this.renderComponent()
}
},
beforeDestroy () {
if (this.autoDestroy) {
this.removeContainer()
}
},
methods: {
removeContainer () {
if (this.container) {
this._component && this._component.$destroy()
this.container.parentNode.removeChild(this.container)
this.container = null
}
},
renderComponent (props = {}, ready) {
const { visible, getComponent, forceRender, getContainer, parent } = this
const self = this
if (visible || parent.$refs._component || forceRender) {
let el = this.componentEl
if (!this.container) {
this.container = getContainer()
el = document.createElement('div')
this.componentEl = el
this.container.appendChild(el)
}
if (!this._component) {
this._component = new Vue({
data: {
comProps: props,
},
parent: self.parent,
el: el,
mounted () {
this.$nextTick(() => {
if (ready) {
ready.call(self)
}
})
},
render () {
return getComponent(this.comProps)
},
})
} else {
this._component.comProps = props
}
}
},
},
render () {
return this.children({
renderComponent: this.renderComponent,
removeContainer: this.removeContainer,
})
},
}

View File

@ -0,0 +1,5 @@
import addDOMEventListener from 'add-dom-event-listener'
export default function addEventListenerWrap (target, eventType, cb) {
return addDOMEventListener(target, eventType, cb)
}

View File

@ -0,0 +1,61 @@
/* @flow */
/**
* Add class with compatibility for SVG since classList is not supported on
* SVG elements in IE
*/
export function addClass (el, cls) {
/* istanbul ignore if */
if (!cls || !(cls = cls.trim())) {
return
}
/* istanbul ignore else */
if (el.classList) {
if (cls.indexOf(' ') > -1) {
cls.split(/\s+/).forEach(c => el.classList.add(c))
} else {
el.classList.add(cls)
}
} else {
const cur = ` ${el.getAttribute('class') || ''} `
if (cur.indexOf(' ' + cls + ' ') < 0) {
el.setAttribute('class', (cur + cls).trim())
}
}
}
/**
* Remove class with compatibility for SVG since classList is not supported on
* SVG elements in IE
*/
export function removeClass (el, cls) {
/* istanbul ignore if */
if (!cls || !(cls = cls.trim())) {
return
}
/* istanbul ignore else */
if (el.classList) {
if (cls.indexOf(' ') > -1) {
cls.split(/\s+/).forEach(c => el.classList.remove(c))
} else {
el.classList.remove(cls)
}
if (!el.classList.length) {
el.removeAttribute('class')
}
} else {
let cur = ` ${el.getAttribute('class') || ''} `
const tar = ' ' + cls + ' '
while (cur.indexOf(tar) >= 0) {
cur = cur.replace(tar, ' ')
}
cur = cur.trim()
if (cur) {
el.setAttribute('class', cur)
} else {
el.removeAttribute('class')
}
}
}

View File

@ -0,0 +1,11 @@
export default function contains (root, n) {
let node = n
while (node) {
if (node === root) {
return true
}
node = node.parentNode
}
return false
}

View File

@ -1,19 +0,0 @@
export type FocusEventHandler = (e: FocusEvent) => void;
export type MouseEventHandler = (e: MouseEvent) => void;
export type KeyboardEventHandler = (e: KeyboardEvent) => void;
export type CompositionEventHandler = (e: CompositionEvent) => void;
export type ClipboardEventHandler = (e: ClipboardEvent) => void;
export type ChangeEventHandler = (e: ChangeEvent) => void;
export type WheelEventHandler = (e: WheelEvent) => void;
export type ChangeEvent = Event & {
target: {
value?: string | undefined;
};
};
export type CheckboxChangeEvent = Event & {
target: {
checked?: boolean;
};
};
export type EventHandler = (...args: any[]) => void;

521
components/_util/KeyCode.js Normal file
View File

@ -0,0 +1,521 @@
/**
* @ignore
* some key-codes definition and utils from closure-library
* @author yiminghe@gmail.com
*/
const KeyCode = {
/**
* MAC_ENTER
*/
MAC_ENTER: 3,
/**
* BACKSPACE
*/
BACKSPACE: 8,
/**
* TAB
*/
TAB: 9,
/**
* NUMLOCK on FF/Safari Mac
*/
NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac
/**
* ENTER
*/
ENTER: 13,
/**
* SHIFT
*/
SHIFT: 16,
/**
* CTRL
*/
CTRL: 17,
/**
* ALT
*/
ALT: 18,
/**
* PAUSE
*/
PAUSE: 19,
/**
* CAPS_LOCK
*/
CAPS_LOCK: 20,
/**
* ESC
*/
ESC: 27,
/**
* SPACE
*/
SPACE: 32,
/**
* PAGE_UP
*/
PAGE_UP: 33, // also NUM_NORTH_EAST
/**
* PAGE_DOWN
*/
PAGE_DOWN: 34, // also NUM_SOUTH_EAST
/**
* END
*/
END: 35, // also NUM_SOUTH_WEST
/**
* HOME
*/
HOME: 36, // also NUM_NORTH_WEST
/**
* LEFT
*/
LEFT: 37, // also NUM_WEST
/**
* UP
*/
UP: 38, // also NUM_NORTH
/**
* RIGHT
*/
RIGHT: 39, // also NUM_EAST
/**
* DOWN
*/
DOWN: 40, // also NUM_SOUTH
/**
* PRINT_SCREEN
*/
PRINT_SCREEN: 44,
/**
* INSERT
*/
INSERT: 45, // also NUM_INSERT
/**
* DELETE
*/
DELETE: 46, // also NUM_DELETE
/**
* ZERO
*/
ZERO: 48,
/**
* ONE
*/
ONE: 49,
/**
* TWO
*/
TWO: 50,
/**
* THREE
*/
THREE: 51,
/**
* FOUR
*/
FOUR: 52,
/**
* FIVE
*/
FIVE: 53,
/**
* SIX
*/
SIX: 54,
/**
* SEVEN
*/
SEVEN: 55,
/**
* EIGHT
*/
EIGHT: 56,
/**
* NINE
*/
NINE: 57,
/**
* QUESTION_MARK
*/
QUESTION_MARK: 63, // needs localization
/**
* A
*/
A: 65,
/**
* B
*/
B: 66,
/**
* C
*/
C: 67,
/**
* D
*/
D: 68,
/**
* E
*/
E: 69,
/**
* F
*/
F: 70,
/**
* G
*/
G: 71,
/**
* H
*/
H: 72,
/**
* I
*/
I: 73,
/**
* J
*/
J: 74,
/**
* K
*/
K: 75,
/**
* L
*/
L: 76,
/**
* M
*/
M: 77,
/**
* N
*/
N: 78,
/**
* O
*/
O: 79,
/**
* P
*/
P: 80,
/**
* Q
*/
Q: 81,
/**
* R
*/
R: 82,
/**
* S
*/
S: 83,
/**
* T
*/
T: 84,
/**
* U
*/
U: 85,
/**
* V
*/
V: 86,
/**
* W
*/
W: 87,
/**
* X
*/
X: 88,
/**
* Y
*/
Y: 89,
/**
* Z
*/
Z: 90,
/**
* META
*/
META: 91, // WIN_KEY_LEFT
/**
* WIN_KEY_RIGHT
*/
WIN_KEY_RIGHT: 92,
/**
* CONTEXT_MENU
*/
CONTEXT_MENU: 93,
/**
* NUM_ZERO
*/
NUM_ZERO: 96,
/**
* NUM_ONE
*/
NUM_ONE: 97,
/**
* NUM_TWO
*/
NUM_TWO: 98,
/**
* NUM_THREE
*/
NUM_THREE: 99,
/**
* NUM_FOUR
*/
NUM_FOUR: 100,
/**
* NUM_FIVE
*/
NUM_FIVE: 101,
/**
* NUM_SIX
*/
NUM_SIX: 102,
/**
* NUM_SEVEN
*/
NUM_SEVEN: 103,
/**
* NUM_EIGHT
*/
NUM_EIGHT: 104,
/**
* NUM_NINE
*/
NUM_NINE: 105,
/**
* NUM_MULTIPLY
*/
NUM_MULTIPLY: 106,
/**
* NUM_PLUS
*/
NUM_PLUS: 107,
/**
* NUM_MINUS
*/
NUM_MINUS: 109,
/**
* NUM_PERIOD
*/
NUM_PERIOD: 110,
/**
* NUM_DIVISION
*/
NUM_DIVISION: 111,
/**
* F1
*/
F1: 112,
/**
* F2
*/
F2: 113,
/**
* F3
*/
F3: 114,
/**
* F4
*/
F4: 115,
/**
* F5
*/
F5: 116,
/**
* F6
*/
F6: 117,
/**
* F7
*/
F7: 118,
/**
* F8
*/
F8: 119,
/**
* F9
*/
F9: 120,
/**
* F10
*/
F10: 121,
/**
* F11
*/
F11: 122,
/**
* F12
*/
F12: 123,
/**
* NUMLOCK
*/
NUMLOCK: 144,
/**
* SEMICOLON
*/
SEMICOLON: 186, // needs localization
/**
* DASH
*/
DASH: 189, // needs localization
/**
* EQUALS
*/
EQUALS: 187, // needs localization
/**
* COMMA
*/
COMMA: 188, // needs localization
/**
* PERIOD
*/
PERIOD: 190, // needs localization
/**
* SLASH
*/
SLASH: 191, // needs localization
/**
* APOSTROPHE
*/
APOSTROPHE: 192, // needs localization
/**
* SINGLE_QUOTE
*/
SINGLE_QUOTE: 222, // needs localization
/**
* OPEN_SQUARE_BRACKET
*/
OPEN_SQUARE_BRACKET: 219, // needs localization
/**
* BACKSLASH
*/
BACKSLASH: 220, // needs localization
/**
* CLOSE_SQUARE_BRACKET
*/
CLOSE_SQUARE_BRACKET: 221, // needs localization
/**
* WIN_KEY
*/
WIN_KEY: 224,
/**
* MAC_FF_META
*/
MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
/**
* WIN_IME
*/
WIN_IME: 229,
}
/*
whether text and modified key is entered at the same time.
*/
KeyCode.isTextModifyingKeyEvent = function isTextModifyingKeyEvent (e) {
const keyCode = e.keyCode
if (e.altKey && !e.ctrlKey || e.metaKey ||
// Function keys don't generate text
keyCode >= KeyCode.F1 && keyCode <= KeyCode.F12) {
return false
}
// The following keys are quite harmless, even in combination with
// CTRL, ALT or SHIFT.
switch (keyCode) {
case KeyCode.ALT:
case KeyCode.CAPS_LOCK:
case KeyCode.CONTEXT_MENU:
case KeyCode.CTRL:
case KeyCode.DOWN:
case KeyCode.END:
case KeyCode.ESC:
case KeyCode.HOME:
case KeyCode.INSERT:
case KeyCode.LEFT:
case KeyCode.MAC_FF_META:
case KeyCode.META:
case KeyCode.NUMLOCK:
case KeyCode.NUM_CENTER:
case KeyCode.PAGE_DOWN:
case KeyCode.PAGE_UP:
case KeyCode.PAUSE:
case KeyCode.PRINT_SCREEN:
case KeyCode.RIGHT:
case KeyCode.SHIFT:
case KeyCode.UP:
case KeyCode.WIN_KEY:
case KeyCode.WIN_KEY_RIGHT:
return false
default:
return true
}
}
/*
whether character is entered.
*/
KeyCode.isCharacterKey = function isCharacterKey (keyCode) {
if (keyCode >= KeyCode.ZERO &&
keyCode <= KeyCode.NINE) {
return true
}
if (keyCode >= KeyCode.NUM_ZERO &&
keyCode <= KeyCode.NUM_MULTIPLY) {
return true
}
if (keyCode >= KeyCode.A &&
keyCode <= KeyCode.Z) {
return true
}
// Safari sends zero key code for non-latin characters.
if (window.navigation.userAgent.indexOf('WebKit') !== -1 && keyCode === 0) {
return true
}
switch (keyCode) {
case KeyCode.SPACE:
case KeyCode.QUESTION_MARK:
case KeyCode.NUM_PLUS:
case KeyCode.NUM_MINUS:
case KeyCode.NUM_PERIOD:
case KeyCode.NUM_DIVISION:
case KeyCode.SEMICOLON:
case KeyCode.DASH:
case KeyCode.EQUALS:
case KeyCode.COMMA:
case KeyCode.PERIOD:
case KeyCode.SLASH:
case KeyCode.APOSTROPHE:
case KeyCode.SINGLE_QUOTE:
case KeyCode.OPEN_SQUARE_BRACKET:
case KeyCode.BACKSLASH:
case KeyCode.CLOSE_SQUARE_BRACKET:
return true
default:
return false
}
}
export default KeyCode

View File

@ -1,522 +0,0 @@
/**
* @ignore
* some key-codes definition and utils from closure-library
* @author yiminghe@gmail.com
*/
const KeyCode = {
/**
* MAC_ENTER
*/
MAC_ENTER: 3,
/**
* BACKSPACE
*/
BACKSPACE: 8,
/**
* TAB
*/
TAB: 9,
/**
* NUMLOCK on FF/Safari Mac
*/
NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac
/**
* ENTER
*/
ENTER: 13,
/**
* SHIFT
*/
SHIFT: 16,
/**
* CTRL
*/
CTRL: 17,
/**
* ALT
*/
ALT: 18,
/**
* PAUSE
*/
PAUSE: 19,
/**
* CAPS_LOCK
*/
CAPS_LOCK: 20,
/**
* ESC
*/
ESC: 27,
/**
* SPACE
*/
SPACE: 32,
/**
* PAGE_UP
*/
PAGE_UP: 33, // also NUM_NORTH_EAST
/**
* PAGE_DOWN
*/
PAGE_DOWN: 34, // also NUM_SOUTH_EAST
/**
* END
*/
END: 35, // also NUM_SOUTH_WEST
/**
* HOME
*/
HOME: 36, // also NUM_NORTH_WEST
/**
* LEFT
*/
LEFT: 37, // also NUM_WEST
/**
* UP
*/
UP: 38, // also NUM_NORTH
/**
* RIGHT
*/
RIGHT: 39, // also NUM_EAST
/**
* DOWN
*/
DOWN: 40, // also NUM_SOUTH
/**
* PRINT_SCREEN
*/
PRINT_SCREEN: 44,
/**
* INSERT
*/
INSERT: 45, // also NUM_INSERT
/**
* DELETE
*/
DELETE: 46, // also NUM_DELETE
/**
* ZERO
*/
ZERO: 48,
/**
* ONE
*/
ONE: 49,
/**
* TWO
*/
TWO: 50,
/**
* THREE
*/
THREE: 51,
/**
* FOUR
*/
FOUR: 52,
/**
* FIVE
*/
FIVE: 53,
/**
* SIX
*/
SIX: 54,
/**
* SEVEN
*/
SEVEN: 55,
/**
* EIGHT
*/
EIGHT: 56,
/**
* NINE
*/
NINE: 57,
/**
* QUESTION_MARK
*/
QUESTION_MARK: 63, // needs localization
/**
* A
*/
A: 65,
/**
* B
*/
B: 66,
/**
* C
*/
C: 67,
/**
* D
*/
D: 68,
/**
* E
*/
E: 69,
/**
* F
*/
F: 70,
/**
* G
*/
G: 71,
/**
* H
*/
H: 72,
/**
* I
*/
I: 73,
/**
* J
*/
J: 74,
/**
* K
*/
K: 75,
/**
* L
*/
L: 76,
/**
* M
*/
M: 77,
/**
* N
*/
N: 78,
/**
* O
*/
O: 79,
/**
* P
*/
P: 80,
/**
* Q
*/
Q: 81,
/**
* R
*/
R: 82,
/**
* S
*/
S: 83,
/**
* T
*/
T: 84,
/**
* U
*/
U: 85,
/**
* V
*/
V: 86,
/**
* W
*/
W: 87,
/**
* X
*/
X: 88,
/**
* Y
*/
Y: 89,
/**
* Z
*/
Z: 90,
/**
* META
*/
META: 91, // WIN_KEY_LEFT
/**
* WIN_KEY_RIGHT
*/
WIN_KEY_RIGHT: 92,
/**
* CONTEXT_MENU
*/
CONTEXT_MENU: 93,
/**
* NUM_ZERO
*/
NUM_ZERO: 96,
/**
* NUM_ONE
*/
NUM_ONE: 97,
/**
* NUM_TWO
*/
NUM_TWO: 98,
/**
* NUM_THREE
*/
NUM_THREE: 99,
/**
* NUM_FOUR
*/
NUM_FOUR: 100,
/**
* NUM_FIVE
*/
NUM_FIVE: 101,
/**
* NUM_SIX
*/
NUM_SIX: 102,
/**
* NUM_SEVEN
*/
NUM_SEVEN: 103,
/**
* NUM_EIGHT
*/
NUM_EIGHT: 104,
/**
* NUM_NINE
*/
NUM_NINE: 105,
/**
* NUM_MULTIPLY
*/
NUM_MULTIPLY: 106,
/**
* NUM_PLUS
*/
NUM_PLUS: 107,
/**
* NUM_MINUS
*/
NUM_MINUS: 109,
/**
* NUM_PERIOD
*/
NUM_PERIOD: 110,
/**
* NUM_DIVISION
*/
NUM_DIVISION: 111,
/**
* F1
*/
F1: 112,
/**
* F2
*/
F2: 113,
/**
* F3
*/
F3: 114,
/**
* F4
*/
F4: 115,
/**
* F5
*/
F5: 116,
/**
* F6
*/
F6: 117,
/**
* F7
*/
F7: 118,
/**
* F8
*/
F8: 119,
/**
* F9
*/
F9: 120,
/**
* F10
*/
F10: 121,
/**
* F11
*/
F11: 122,
/**
* F12
*/
F12: 123,
/**
* NUMLOCK
*/
NUMLOCK: 144,
/**
* SEMICOLON
*/
SEMICOLON: 186, // needs localization
/**
* DASH
*/
DASH: 189, // needs localization
/**
* EQUALS
*/
EQUALS: 187, // needs localization
/**
* COMMA
*/
COMMA: 188, // needs localization
/**
* PERIOD
*/
PERIOD: 190, // needs localization
/**
* SLASH
*/
SLASH: 191, // needs localization
/**
* APOSTROPHE
*/
APOSTROPHE: 192, // needs localization
/**
* SINGLE_QUOTE
*/
SINGLE_QUOTE: 222, // needs localization
/**
* OPEN_SQUARE_BRACKET
*/
OPEN_SQUARE_BRACKET: 219, // needs localization
/**
* BACKSLASH
*/
BACKSLASH: 220, // needs localization
/**
* CLOSE_SQUARE_BRACKET
*/
CLOSE_SQUARE_BRACKET: 221, // needs localization
/**
* WIN_KEY
*/
WIN_KEY: 224,
/**
* MAC_FF_META
*/
MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
/**
* WIN_IME
*/
WIN_IME: 229,
// ======================== Function ========================
/**
* whether text and modified key is entered at the same time.
*/
isTextModifyingKeyEvent: function isTextModifyingKeyEvent(e: KeyboardEvent) {
const { keyCode } = e;
if (
(e.altKey && !e.ctrlKey) ||
e.metaKey ||
// Function keys don't generate text
(keyCode >= KeyCode.F1 && keyCode <= KeyCode.F12)
) {
return false;
}
// The following keys are quite harmless, even in combination with
// CTRL, ALT or SHIFT.
switch (keyCode) {
case KeyCode.ALT:
case KeyCode.CAPS_LOCK:
case KeyCode.CONTEXT_MENU:
case KeyCode.CTRL:
case KeyCode.DOWN:
case KeyCode.END:
case KeyCode.ESC:
case KeyCode.HOME:
case KeyCode.INSERT:
case KeyCode.LEFT:
case KeyCode.MAC_FF_META:
case KeyCode.META:
case KeyCode.NUMLOCK:
case KeyCode.NUM_CENTER:
case KeyCode.PAGE_DOWN:
case KeyCode.PAGE_UP:
case KeyCode.PAUSE:
case KeyCode.PRINT_SCREEN:
case KeyCode.RIGHT:
case KeyCode.SHIFT:
case KeyCode.UP:
case KeyCode.WIN_KEY:
case KeyCode.WIN_KEY_RIGHT:
return false;
default:
return true;
}
},
/**
* whether character is entered.
*/
isCharacterKey: function isCharacterKey(keyCode: number) {
if (keyCode >= KeyCode.ZERO && keyCode <= KeyCode.NINE) {
return true;
}
if (keyCode >= KeyCode.NUM_ZERO && keyCode <= KeyCode.NUM_MULTIPLY) {
return true;
}
if (keyCode >= KeyCode.A && keyCode <= KeyCode.Z) {
return true;
}
// Safari sends zero key code for non-latin characters.
if (window.navigator.userAgent.indexOf('WebKit') !== -1 && keyCode === 0) {
return true;
}
switch (keyCode) {
case KeyCode.SPACE:
case KeyCode.QUESTION_MARK:
case KeyCode.NUM_PLUS:
case KeyCode.NUM_MINUS:
case KeyCode.NUM_PERIOD:
case KeyCode.NUM_DIVISION:
case KeyCode.SEMICOLON:
case KeyCode.DASH:
case KeyCode.EQUALS:
case KeyCode.COMMA:
case KeyCode.PERIOD:
case KeyCode.SLASH:
case KeyCode.APOSTROPHE:
case KeyCode.SINGLE_QUOTE:
case KeyCode.OPEN_SQUARE_BRACKET:
case KeyCode.BACKSLASH:
case KeyCode.CLOSE_SQUARE_BRACKET:
return true;
default:
return false;
}
},
};
export default KeyCode;

View File

@ -1,72 +0,0 @@
import PropTypes from './vue-types';
import {
defineComponent,
nextTick,
onBeforeMount,
onMounted,
onUpdated,
Teleport,
watch,
} from 'vue';
import { useInjectPortal } from '../vc-trigger/context';
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'Portal',
inheritAttrs: false,
props: {
getContainer: PropTypes.func.isRequired,
didUpdate: Function,
},
setup(props, { slots }) {
let isSSR = true;
// getContainer 不会改变,不用响应式
let container: HTMLElement;
const { shouldRender } = useInjectPortal();
function setContainer() {
if (shouldRender.value) {
container = props.getContainer();
}
}
onBeforeMount(() => {
isSSR = false;
// drawer
setContainer();
});
onMounted(() => {
if (container) return;
// https://github.com/vueComponent/ant-design-vue/issues/6937
setContainer();
});
const stopWatch = watch(shouldRender, () => {
if (shouldRender.value && !container) {
container = props.getContainer();
}
if (container) {
stopWatch();
}
});
onUpdated(() => {
nextTick(() => {
if (shouldRender.value) {
props.didUpdate?.(props);
}
});
});
// onBeforeUnmount(() => {
// if (container && container.parentNode) {
// container.parentNode.removeChild(container);
// }
// });
return () => {
if (!shouldRender.value) return null;
if (isSSR) {
return slots.default?.();
}
return container ? <Teleport to={container} v-slots={slots}></Teleport> : null;
};
},
});

View File

@ -1,191 +0,0 @@
import PropTypes from './vue-types';
import Portal from './Portal';
import {
defineComponent,
shallowRef,
watch,
onMounted,
onBeforeUnmount,
onUpdated,
nextTick,
computed,
} from 'vue';
import canUseDom from './canUseDom';
import raf from './raf';
import { booleanType } from './type';
import useScrollLocker from './hooks/useScrollLocker';
let openCount = 0;
const supportDom = canUseDom();
/** @private Test usage only */
export function getOpenCount() {
return process.env.NODE_ENV === 'test' ? openCount : 0;
}
const getParent = (getContainer: GetContainer) => {
if (!supportDom) {
return null;
}
if (getContainer) {
if (typeof getContainer === 'string') {
return document.querySelectorAll(getContainer)[0] as HTMLElement;
}
if (typeof getContainer === 'function') {
return getContainer();
}
if (typeof getContainer === 'object' && getContainer instanceof window.HTMLElement) {
return getContainer;
}
}
return document.body;
};
export type GetContainer = string | HTMLElement | (() => HTMLElement);
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'PortalWrapper',
inheritAttrs: false,
props: {
wrapperClassName: String,
forceRender: { type: Boolean, default: undefined },
getContainer: PropTypes.any,
visible: { type: Boolean, default: undefined },
autoLock: booleanType(),
didUpdate: Function,
},
setup(props, { slots }) {
const container = shallowRef<HTMLElement>();
const componentRef = shallowRef();
const rafId = shallowRef<number>();
const triggerUpdate = shallowRef(1);
const defaultContainer = canUseDom() && document.createElement('div');
const removeCurrentContainer = () => {
// Portal will remove from `parentNode`.
// Let's handle this again to avoid refactor issue.
if (container.value === defaultContainer) {
container.value?.parentNode?.removeChild(container.value);
}
container.value = null;
};
let parent: HTMLElement = null;
const attachToParent = (force = false) => {
if (force || (container.value && !container.value.parentNode)) {
parent = getParent(props.getContainer);
if (parent) {
parent.appendChild(container.value);
return true;
}
return false;
}
return true;
};
const getContainer = () => {
if (!supportDom) {
return null;
}
if (!container.value) {
container.value = defaultContainer;
attachToParent(true);
}
setWrapperClassName();
return container.value;
};
const setWrapperClassName = () => {
const { wrapperClassName } = props;
if (container.value && wrapperClassName && wrapperClassName !== container.value.className) {
container.value.className = wrapperClassName;
}
};
onUpdated(() => {
setWrapperClassName();
attachToParent();
});
useScrollLocker(
computed(() => {
return (
props.autoLock &&
props.visible &&
canUseDom() &&
(container.value === document.body || container.value === defaultContainer)
);
}),
);
onMounted(() => {
let init = false;
watch(
[() => props.visible, () => props.getContainer],
([visible, getContainer], [prevVisible, prevGetContainer]) => {
// Update count
if (supportDom) {
parent = getParent(props.getContainer);
if (parent === document.body) {
if (visible && !prevVisible) {
openCount += 1;
} else if (init) {
openCount -= 1;
}
}
}
if (init) {
// Clean up container if needed
const getContainerIsFunc =
typeof getContainer === 'function' && typeof prevGetContainer === 'function';
if (
getContainerIsFunc
? getContainer.toString() !== prevGetContainer.toString()
: getContainer !== prevGetContainer
) {
removeCurrentContainer();
}
}
init = true;
},
{ immediate: true, flush: 'post' },
);
nextTick(() => {
if (!attachToParent()) {
rafId.value = raf(() => {
triggerUpdate.value += 1;
});
}
});
});
onBeforeUnmount(() => {
const { visible } = props;
if (supportDom && parent === document.body) {
// 离开时不会 render 导到离开时数值不变,改用 func 。。
openCount = visible && openCount ? openCount - 1 : openCount;
}
removeCurrentContainer();
raf.cancel(rafId.value);
});
return () => {
const { forceRender, visible } = props;
let portal = null;
const childProps = {
getOpenCount: () => openCount,
getContainer,
};
if (triggerUpdate.value && (forceRender || visible || componentRef.value)) {
portal = (
<Portal
getContainer={getContainer}
ref={componentRef}
didUpdate={props.didUpdate}
v-slots={{ default: () => slots.default?.(childProps) }}
></Portal>
);
}
return portal;
};
},
});

View File

@ -0,0 +1,10 @@
export default {
methods: {
setState (state, callback) {
Object.assign(this.$data, state)
this.$nextTick(() => {
callback && callback()
})
},
},
}

View File

@ -1,13 +0,0 @@
import { defineComponent } from 'vue';
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'Portal',
inheritAttrs: false,
props: ['getContainer'],
setup(_props, { slots }) {
return () => {
return slots.default?.();
};
},
});

View File

@ -1,11 +0,0 @@
import { defineComponent } from 'vue';
import { customRenderSlot } from '../vnode';
export default defineComponent({
name: 'RenderSlot',
setup(_props, { slots }) {
return () => {
return customRenderSlot(slots, 'default', {}, () => ['default value']);
};
},
});

View File

@ -1,13 +0,0 @@
import { easeInOutCubic } from '../easings';
describe('Test easings', () => {
it('easeInOutCubic return value', () => {
const nums = [];
// eslint-disable-next-line no-plusplus
for (let index = 0; index < 5; index++) {
nums.push(easeInOutCubic(index, 1, 5, 4));
}
expect(nums).toEqual([1, 1.25, 3, 4.75, 5]);
});
});

View File

@ -1,56 +0,0 @@
import scrollTo from '../scrollTo';
describe('Test ScrollTo function', () => {
let dateNowMock;
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
beforeEach(() => {
dateNowMock = jest
.spyOn(Date, 'now')
.mockImplementationOnce(() => 0)
.mockImplementationOnce(() => 1000);
});
afterEach(() => {
dateNowMock.mockRestore();
});
it('test scrollTo', async () => {
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => {
window.scrollY = y;
window.pageYOffset = y;
});
scrollTo(1000);
jest.runAllTimers();
expect(window.pageYOffset).toBe(1000);
scrollToSpy.mockRestore();
});
it('test callback - option', async () => {
const cbMock = jest.fn();
scrollTo(1000, {
callback: cbMock,
});
jest.runAllTimers();
expect(cbMock).toHaveBeenCalledTimes(1);
});
it('test getContainer - option', async () => {
const div = document.createElement('div');
scrollTo(1000, {
getContainer: () => div,
});
jest.runAllTimers();
expect(div.scrollTop).toBe(1000);
});
});

View File

@ -1,8 +0,0 @@
import UnreachableException from '../unreachableException';
describe('UnreachableException', () => {
it('error thrown matches snapshot', () => {
const exception = new UnreachableException('some value');
expect(exception.error.message).toMatchInlineSnapshot(`"unreachable case: \\"some value\\""`);
});
});

View File

@ -1,26 +0,0 @@
import RenderSlot from '../__mocks__/RenderSlot';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
describe('render slot content', () => {
it('renders slot content', () => {
const wrapper = mount(RenderSlot, {
slots: {
default: () => 'This is slot content',
},
});
expect(wrapper.html()).toContain('This is slot content');
});
it('render default value when slot is fragment', async () => {
const wrapper = mount(RenderSlot, {
slots: {
default: () => <></>,
},
});
await nextTick();
expect(wrapper.html()).toContain('default value');
});
});

View File

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

View File

@ -1,5 +0,0 @@
function canUseDom() {
return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
}
export default canUseDom;

View File

@ -1,27 +0,0 @@
import { isArray, isString, isObject } from './util';
function classNames(...args: any[]) {
const classes = [];
for (let i = 0; i < args.length; i++) {
const value = args[i];
if (!value) continue;
if (isString(value)) {
classes.push(value);
} else if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
const inner = classNames(value[i]);
if (inner) {
classes.push(inner);
}
}
} else if (isObject(value)) {
for (const name in value) {
if (value[name]) {
classes.push(name);
}
}
}
}
return classes.join(' ');
}
export default classNames;

View File

@ -1,50 +0,0 @@
import { nextTick } from 'vue';
import { addClass, removeClass } from '../vc-util/Dom/class';
import type { CSSMotionProps } from './transition';
const collapseMotion = (name = 'ant-motion-collapse', appear = true): CSSMotionProps => {
return {
name,
appear,
css: true,
onBeforeEnter: (node: HTMLDivElement) => {
node.style.height = '0px';
node.style.opacity = '0';
addClass(node, name);
},
onEnter: (node: HTMLDivElement) => {
nextTick(() => {
node.style.height = `${node.scrollHeight}px`;
node.style.opacity = '1';
});
},
onAfterEnter: (node: HTMLDivElement) => {
if (node) {
removeClass(node, name);
node.style.height = null;
node.style.opacity = null;
}
},
onBeforeLeave: (node: HTMLDivElement) => {
addClass(node, name);
node.style.height = `${node.offsetHeight}px`;
node.style.opacity = null;
},
onLeave: (node: HTMLDivElement) => {
setTimeout(() => {
node.style.height = '0px';
node.style.opacity = '0';
});
},
onAfterLeave: (node: HTMLDivElement) => {
if (node) {
removeClass(node, name);
if (node.style) {
node.style.height = null;
node.style.opacity = null;
}
}
},
};
};
export default collapseMotion;

View File

@ -1,34 +0,0 @@
import type { PresetColorKey } from '../theme/interface';
import { PresetColors } from '../theme/interface';
type InverseColor = `${PresetColorKey}-inverse`;
const inverseColors = PresetColors.map<InverseColor>(color => `${color}-inverse`);
export const PresetStatusColorTypes = [
'success',
'processing',
'error',
'default',
'warning',
] as const;
export type PresetColorType = PresetColorKey | InverseColor;
export type PresetStatusColorType = (typeof PresetStatusColorTypes)[number];
/**
* determine if the color keyword belongs to the `Ant Design` {@link PresetColors}.
* @param color color to be judged
* @param includeInverse whether to include reversed colors
*/
export function isPresetColor(color?: any, includeInverse = true) {
if (includeInverse) {
return [...inverseColors, ...PresetColors].includes(color);
}
return PresetColors.includes(color);
}
export function isPresetStatusColor(color?: any): color is PresetStatusColorType {
return PresetStatusColorTypes.includes(color);
}

View File

@ -1,168 +0,0 @@
/**
* source by `component-classes`
* https://github.com/component/classes.git
*/
import indexOf from 'lodash-es/indexOf';
/**
* Whitespace regexp.
*/
const re = /\s+/;
export class ClassList {
el: Element;
list: DOMTokenList;
constructor(el: Element) {
if (!el || !el.nodeType) {
throw new Error('A DOM element reference is required');
}
this.el = el;
this.list = el.classList;
}
array() {
const className = this.el.getAttribute('class') || '';
const str = className.replace(/^\s+|\s+$/g, '');
const arr = str.split(re);
if ('' === arr[0]) arr.shift();
return arr;
}
/**
* Add class `name` if not already present.
*
* @param {String} name
* @return {ClassList}
* @api public
*/
add(name: string): ClassList {
// classList
if (this.list) {
this.list.add(name);
return this;
}
// fallback
const arr = this.array();
const i = indexOf(arr, name);
if (!~i) arr.push(name);
this.el.className = arr.join(' ');
return this;
}
/**
* Remove class `name` when present, or
* pass a regular expression to remove
* any which match.
*
* @param {String|RegExp} name
* @return {ClassList}
* @api public
*/
remove(name: string | RegExp): ClassList {
if ('[object RegExp]' === toString.call(name)) {
return this._removeMatching(name as RegExp);
}
// classList
if (this.list) {
this.list.remove(name as string);
return this;
}
// fallback
const arr = this.array();
const i = indexOf(arr, name);
if (~i) arr.splice(i, 1);
this.el.className = arr.join(' ');
return this;
}
/**
* Remove all classes matching `re`.
*
* @param {RegExp} re
* @return {ClassList}
* @api private
*/
_removeMatching(re: RegExp): ClassList {
const arr = this.array();
for (let i = 0; i < arr.length; i++) {
if (re.test(arr[i])) {
this.remove(arr[i]);
}
}
return this;
}
/**
* Toggle class `name`, can force state via `force`.
*
* For browsers that support classList, but do not support `force` yet,
* the mistake will be detected and corrected.
*
* @param {String} name
* @param {Boolean} force
* @return {ClassList}
* @api public
*/
toggle(name: string, force: boolean): ClassList {
// classList
if (this.list) {
if ('undefined' !== typeof force) {
if (force !== this.list.toggle(name, force)) {
this.list.toggle(name); // toggle again to correct
}
} else {
this.list.toggle(name);
}
return this;
}
// fallback
if ('undefined' !== typeof force) {
if (!force) {
this.remove(name);
} else {
this.add(name);
}
} else {
if (this.has(name)) {
this.remove(name);
} else {
this.add(name);
}
}
return this;
}
/**
* Check if class `name` is present.
*
* @param {String} name
* @api public
*/
has(name: string) {
return this.list ? this.list.contains(name) : !!~indexOf(this.array(), name);
}
/**
* Check if class `name` is present.
*
* @param {String} name
* @api public
*/
contains(name: string) {
return this.has(name);
}
}
/**
* Wrap `el` in a `ClassList`.
*
* @param {Element} el
* @return {ClassList}
* @api public
*/
export default function (el: Element): ClassList {
return new ClassList(el);
}

View File

@ -1,120 +0,0 @@
import deselectCurrent from './toggle-selection';
interface Options {
debug?: boolean;
message?: string;
format?: string; // MIME type
onCopy?: (clipboardData: object) => void;
}
const clipboardToIE11Formatting = {
'text/plain': 'Text',
'text/html': 'Url',
default: 'Text',
};
const defaultMessage = 'Copy to clipboard: #{key}, Enter';
function format(message: string) {
const copyKey = (/mac os x/i.test(navigator.userAgent) ? '⌘' : 'Ctrl') + '+C';
return message.replace(/#{\s*key\s*}/g, copyKey);
}
function copy(text: string, options?: Options): boolean {
let message,
reselectPrevious,
range,
selection,
mark,
success = false;
if (!options) {
options = {};
}
const debug = options.debug || false;
try {
reselectPrevious = deselectCurrent();
range = document.createRange();
selection = document.getSelection();
mark = document.createElement('span');
mark.textContent = text;
// reset user styles for span element
mark.style.all = 'unset';
// prevents scrolling to the end of the page
mark.style.position = 'fixed';
mark.style.top = 0;
mark.style.clip = 'rect(0, 0, 0, 0)';
// used to preserve spaces and line breaks
mark.style.whiteSpace = 'pre';
// do not inherit user-select (it may be `none`)
mark.style.webkitUserSelect = 'text';
mark.style.MozUserSelect = 'text';
mark.style.msUserSelect = 'text';
mark.style.userSelect = 'text';
mark.addEventListener('copy', function (e) {
e.stopPropagation();
if (options.format) {
e.preventDefault();
if (typeof e.clipboardData === 'undefined') {
// IE 11
debug && console.warn('unable to use e.clipboardData');
debug && console.warn('trying IE specific stuff');
(window as any).clipboardData.clearData();
const format =
clipboardToIE11Formatting[options.format] || clipboardToIE11Formatting['default'];
(window as any).clipboardData.setData(format, text);
} else {
// all other browsers
e.clipboardData.clearData();
e.clipboardData.setData(options.format, text);
}
}
if (options.onCopy) {
e.preventDefault();
options.onCopy(e.clipboardData);
}
});
document.body.appendChild(mark);
range.selectNodeContents(mark);
selection.addRange(range);
const successful = document.execCommand('copy');
if (!successful) {
throw new Error('copy command was unsuccessful');
}
success = true;
} catch (err) {
debug && console.error('unable to copy using execCommand: ', err);
debug && console.warn('trying IE specific stuff');
try {
(window as any).clipboardData.setData(options.format || 'text', text);
options.onCopy && options.onCopy((window as any).clipboardData);
success = true;
} catch (err) {
debug && console.error('unable to copy using clipboardData: ', err);
debug && console.error('falling back to prompt');
message = format('message' in options ? options.message : defaultMessage);
window.prompt(message, text);
}
} finally {
if (selection) {
if (typeof selection.removeRange == 'function') {
selection.removeRange(range);
} else {
selection.removeAllRanges();
}
}
if (mark) {
document.body.removeChild(mark);
}
reselectPrevious();
}
return success;
}
export default copy;

View File

@ -1,41 +0,0 @@
// copy from https://github.com/sudodoki/toggle-selection
// refactor to esm
const deselectCurrent = (): (() => void) => {
const selection = document.getSelection();
if (!selection.rangeCount) {
return function () {};
}
let active = document.activeElement as any;
const ranges = [];
for (let i = 0; i < selection.rangeCount; i++) {
ranges.push(selection.getRangeAt(i));
}
switch (
active.tagName.toUpperCase() // .toUpperCase handles XHTML
) {
case 'INPUT':
case 'TEXTAREA':
active.blur();
break;
default:
active = null;
break;
}
selection.removeAllRanges();
return function () {
selection.type === 'Caret' && selection.removeAllRanges();
if (!selection.rangeCount) {
ranges.forEach(function (range) {
selection.addRange(range);
});
}
active && active.focus();
};
};
export default deselectCurrent;

View File

@ -0,0 +1,22 @@
/**
* Safe chained function
*
* Will only create a new function if needed,
* otherwise will pass back existing functions or null.
*
* @returns {function|null}
*/
export default function createChainedFunction () {
const args = [].slice.call(arguments, 0)
if (args.length === 1) {
return args[0]
}
return function chainedFunction () {
for (let i = 0; i < args.length; i++) {
if (args[i] && args[i].apply) {
args[i].apply(this, arguments)
}
}
}
}

View File

@ -1,22 +0,0 @@
import { inject, provide, reactive, watchEffect } from 'vue';
function createContext<T extends Record<string, any>>(defaultValue?: T) {
const contextKey = Symbol('contextKey');
const useProvide = (props: T, newProps?: T) => {
const mergedProps = reactive<T>({} as T);
provide(contextKey, mergedProps);
watchEffect(() => {
Object.assign(mergedProps, props, newProps || {});
});
return mergedProps;
};
const useInject = () => {
return inject(contextKey, defaultValue as T) || ({} as T);
};
return {
useProvide,
useInject,
};
}
export default createContext;

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