Compare commits

..

120 Commits
main ... 1.x

Author SHA1 Message Date
tangjinzhou 19b005867f refactor: remove Google Ads components from API and layout 2025-09-20 14:52:21 +08:00
tangjinzhou e8a1a4a217 docs: update image URLs and remove Alipay/WeChat sponsorship links 2025-09-20 14:51:42 +08:00
tangjinzhou 69d5aa795a chore: update package.json scripts 2025-09-19 19:16:17 +08:00
tangjinzhou bda27eb39b refactor: remove surely form references 2025-09-19 17:27:39 +08:00
tangjinzhou 4136b3b62a docs: update doc url 2023-03-15 16:58:06 +08:00
tangjinzhou 43a48ed422 docs: update bottom banner 2023-03-15 14:08:56 +08:00
tangjinzhou 2afccac35e docs: add qq number & form 2023-03-15 12:26:21 +08:00
tangjinzhou dac22759db docs: add jeecg sponsor 2022-09-02 14:44:59 +08:00
tangjinzhou 3a85220a57 doc: update ad 2022-03-19 16:46:03 +08:00
tangjinzhou acaad27135 docs: update surelyvue 2022-01-27 15:47:36 +08:00
zkwolf 80da77aee0 doc: copy icon #4389 (#4911) 2022-01-27 15:47:36 +08:00
tangjinzhou 773ca392d8 doc: update footer 2022-01-27 15:47:36 +08:00
zkwolf 24ce72ef83 fix: directory-tree title slot #4795 (#4807)
close #4795
2022-01-27 15:47:36 +08:00
tangjinzhou 2c81ccc6f0 doc: update 2022-01-27 15:47:36 +08:00
tangjinzhou 7eb0422f79 doc: update doc 2022-01-27 15:47:36 +08:00
tangjinzhou 11e0994012 doc: update v3 & qrcode 2022-01-27 15:47:36 +08:00
WangYang 233ef9f2cf feat(dropdown): add dropdown destroyPopupOnHide type (#4768)
Co-authored-by: WangYang <yang.wang@cue.group>
2022-01-27 15:47:36 +08:00
Jeminas 441024b993
docs:table demo optimize (#5142) 2022-01-11 16:14:31 +08:00
zhouxinyong 115ca4d8ec
docs: add @formily/antdv link (#5093) 2021-12-28 22:00:03 +08:00
ajuner e70738137e
fix(range-picker): separator error (#5059) 2021-12-21 16:38:59 +08:00
ajuner ef7d0cf0d2
fix(input): allowClear in ie11 (#4699)
close #4679
2021-09-27 09:45:50 +08:00
twobrushes 911ea488bd
perf(table): checkbox performance (#4673)
Co-authored-by: linzhangyu <gebi.lzy@raycloud.com>
2021-09-22 08:31:49 +08:00
tangjinzhou 7779c0469c docs: update doc 2021-08-27 14:07:09 +08:00
tangjinzhou 2b1b81b6ff release 1.7.8 2021-08-27 10:24:13 +08:00
BeADre 7b317a2765
fix(icon): fix the warning of not export default at webpack5 (#4579) 2021-08-27 10:04:33 +08:00
tangjinzhou 74133d18af fix: remove transfer warning #4574 2021-08-26 09:57:37 +08:00
CandyTong f1488e1545
fix(auto-complete): cannot use configProvider prefixCls #4566 (#4568)
Co-authored-by: candychuang <candychuang@tencent.com>

close #4566
2021-08-24 23:01:20 +08:00
tangjinzhou 72b1312209 release 1.7.7 2021-08-07 15:26:34 +08:00
tangjinzhou e99e382ce6 docs: update publicPath 2021-08-07 15:17:38 +08:00
BeADre 89c134a7b7
fix(icon): ensure icon data is valid (#4460)
close #2745
2021-08-04 23:02:56 +08:00
zkwolf b0d226d33e
feat(table): support expandIcon slot (#4448)
close #4444
2021-08-02 17:09:22 +08:00
John 4c559c86ab
docs(space): update `space` document layout #4426 (#4454) 2021-07-31 11:10:50 +08:00
青沛 66219e2b86
docs(update): update documents (#4453)
Co-authored-by: zhangxuelin@xd.com <zhangxuelin@xd.com>
2021-07-31 07:40:55 +08:00
John 6953698385
fix(empty): cannot get `prefixCls` in `configProvider` #4446 (#4447)
close #4446
2021-07-30 16:12:27 +08:00
Darma1106 a4ce890dd6
perf(tabs): active tab color(#4241) (#4417) 2021-07-30 16:05:20 +08:00
tangjinzhou 74007fbb16 Merge branch '1.x' of github.com:vueComponent/ant-design-vue into 1.x 2021-07-14 11:36:35 +08:00
tangjinzhou 833cd47955 docs: update doc 2021-07-14 11:36:25 +08:00
zkwolf 72ca67b103
feat: tree-select support showArrow (#4360) 2021-07-14 10:32:49 +08:00
tangjinzhou 9b5a36186b docs: update anchor feature 2021-07-11 14:54:56 +08:00
zkwolf 4eb26eaec3
feat(input-password): accept global prefixCls (#4280)
* fix(input-password): accept global prefixCls

* fix(input-password): suffix icon style
2021-07-08 09:51:37 +08:00
zkwolf 5c8b82ccf4
feat(tree): support global title slot (#4299)
* feat: global tree title slot

* docs: add context menu demo

* test: update snapshot
2021-07-01 15:21:48 +08:00
tangjinzhou 56991e5488 doc: update table resize demo #4285 2021-06-28 21:09:05 +08:00
undefined e1ac8ce6f0 release 1.7.6 2021-06-26 21:01:17 +08:00
undefined e218afd787 test: update snap 2021-06-26 21:00:58 +08:00
undefined d0c7c0b128 fix: table expanded error #4223 2021-06-26 20:35:53 +08:00
John fb94e7c119
docs(popover): update style #4167 (#4196) 2021-06-10 22:19:19 +08:00
Ken 2f1eb4bbb7
fix: TimePicker input should be readonly like DatePicker. fix #4084 (#4085) 2021-05-23 20:17:24 +08:00
vuthanhbayit 9bb90e78d1
fix: input-number type not work (#4049) 2021-05-10 10:41:32 +08:00
Archer03 23ab83c533
fix: set false as default to validateOnRuleChange in FormModel (#4040) 2021-05-09 20:48:26 +08:00
tangjinzhou 23fb9fae7c release 1.7.5 2021-05-09 15:00:33 +08:00
tangjinzhou f4d8db07fa docs: add ad link 2021-05-09 14:18:09 +08:00
donley 45c7163b58
fix: mode='month' a-date-picker disabledDate prop is invalid (#3988)
* fix: mode='month' a-date-picker disabledDate prop is invalid

* chore: code-factory errors

* chore: remove example codes

* fix: the date-picker disabledDate is invalid when mode is year
2021-05-08 15:09:19 +08:00
Michael Long 3e617bd4d2
docs(table): require `Column.key` in certain cases (#4019)
Prop `Column.key` is required if using template style api (#2501)
2021-05-07 13:38:54 +08:00
zkwolf c0c3b93f0f
chore: remove ci token (#3992)
* chore: remove ci token

* test: update snapshot

* test: update snapshot
2021-04-26 22:17:32 +08:00
John 958e5e488e
fix: input-number ready not work #2971 (#3968) 2021-04-21 15:10:27 +08:00
John bb56898edc
test: update table test case (#3967) 2021-04-21 14:53:25 +08:00
John cc257200e5
fix(1.x/radio): replace 'outline' with 'box-shadow' (#3954)
* fix(radio): replace 'outline' with 'box-shadow'

Closes #3671

* style: remove comment
2021-04-17 08:02:59 +08:00
tangjinzhou 5cec702e0c fix: menu flash #3951 2021-04-17 07:53:08 +08:00
John c2449f568e
docs: keep current path when switching versions (#3927) 2021-04-12 12:33:10 +08:00
John 96709926e8
fix(input): `v-model` modifiers not work (#3817)
* fix(input): `v-model` modifiers not work

* refactor: update
2021-04-11 08:27:39 +08:00
Mr小刘 e95eb61bcb
feat(tbale): 分组表头支持固定-1.x (#3896)
* feat(table): 分组表头支持固定

* docs(table): 增加分组表头固定的英文文档
2021-04-10 21:22:08 +08:00
代娃~ 663aa34d84
docs(table): change rowSelection.selections's default value in chinese docs (#3908) 2021-04-08 11:21:45 +08:00
viruscamp 3761eddb4b
feat: add event update:filterDropdownVisible for Table.Column (#3893)
It's same as event filterDropdownVisibleChange, but can be used with prop as ':filterDropdownVisible.sync="filterDropdownVisible"' for short.
It's the base of other props in Table.Column to add event update:prop to use ':prop.sync' shorthand.
Next events for other props will be update:filteredValue and update:sortDirections.
2021-04-05 10:37:04 +08:00
viruscamp 6fca13fb2c
feat: add event update:expandedRowKeys for Table (#3892)
It's same as event expandedRowsChange, but can be used with prop as ':expandedRowKeys.sync="expandedRowKeys"' for short.
2021-04-04 22:20:34 +08:00
zkwolf 61fa2cfdf6
fix: select trigger disabled option (#3867) 2021-03-28 20:29:45 +08:00
Young 8fc617a4d7
fix:upload component method props not work (#3843)
Co-authored-by: zhenyangliu <liuzhenyang@cfilmcloud.com>
2021-03-27 22:14:57 +08:00
ajuner e0967d9d7e
fix: Microsoft input triggers onchange twice (#3825) 2021-03-20 14:29:23 +08:00
Ken cdde89b17e
fix 'ABackTop visible issue under KeepAlive' (#3802) 2021-03-15 18:17:33 +08:00
tanjinzhou 7c1a14bb5e chore: opensource v1-doc 2021-03-12 15:48:30 +08:00
tanjinzhou 28325c0507 chore: opensource v1-doc 2021-03-12 15:47:29 +08:00
zkwolf 5e139a13e8
fix: revert the default ttab size of card (#3788) 2021-03-12 14:54:07 +08:00
John 976b0b409c
feat: add `dialogStyle` prop (#3794) 2021-03-12 14:52:35 +08:00
zkwolf dfcdf92f7a
fix: drawer esc keydown #3148 (#3790) 2021-03-12 14:51:06 +08:00
Kaworus dced59c65c
feat: add prop tab-size for card (#3762)
* feat: add param tab-size for card

* feat: add param tab-size for card
2021-03-09 15:52:18 +08:00
tangjinzhou 48181af9d6 release 1.7.4 2021-02-28 23:50:22 +08:00
tangjinzhou e427ca15bf perf: table 2021-02-28 23:34:04 +08:00
tangjinzhou 7f4eba3e93 docs: udpate changelog 2021-02-16 16:35:30 +08:00
tangjinzhou 961524b0a7 release 1.7.3 2021-02-16 16:07:12 +08:00
tangjinzhou 391309aad7 style: format code & update snap 2021-02-16 16:05:22 +08:00
tangjinzhou 5e063ba9a3 chore: remove colorpicker 2021-02-16 15:41:00 +08:00
tangjinzhou 22dccf46c5 fix: transformFile not work #3636 2021-02-15 16:07:22 +08:00
pengandpeng 1031e46926
fix: table scroll.x throw error when use expandedRowRender (#3626)
表头固定与展开行不存在冲突,结合使用时不应该报错
2021-02-06 13:46:43 +08:00
zkwolf 76d8408045
fix: closeable icon support in modal method (#3642) 2021-02-06 13:42:04 +08:00
Ken 48bf9ff1b5
fix: menu forceSubMenuRender not work #3615 (#3616) 2021-01-29 21:16:03 +08:00
zkwolf 96e5e836b7
fix: disabled tabPane can be actived #3575 (#3604) 2021-01-27 23:16:47 +08:00
Hyphon e179dedb4a
fix(date-picker): fix props(decade) problem for 1.x (#3536)
Co-authored-by: 李艺珅 <l>
2021-01-14 10:05:18 +08:00
Luka Jeran 1e2814608d
refactor: move ConfigConsumerProps to own file (#3524) 2021-01-14 10:03:43 +08:00
ajuner 0f467695e2
fix: add opacity transition (#3510) 2021-01-09 22:09:34 +08:00
John60676 6175fdbb0c
fix: slider accuracy problems 1.x (#3386)
* fix: slider accuracy problems

* refactor: order of operations
2020-12-17 16:28:30 +08:00
言肆 ec064fe8c2
fix(d.ts): space.d.ts #2923 typeScript definition update (#3340)
* fix(d.ts): space.d.ts  #2923

* fix: add Space ts export
2020-12-15 17:03:00 +08:00
tanjinzhou c74c621e7f fix: table sorter not work #3327 2020-12-09 17:32:38 +08:00
zkwolf 8ba75419b6
fix: checkbox can't trigger change (#3285)
* fix: checkbox can't trigger change

* test: add unit test

* chore: update vc-checkbox
2020-12-04 14:01:51 +08:00
John60676 1581ff3057
fix(button): dropdown inside ButtonGroup in the wrong position (#3036) 2020-11-23 13:55:06 +08:00
tanjinzhou 6ecbaaa547 fix: alert close icon style error on safari #3184 2020-11-16 13:03:21 +08:00
Emmanuel Pastor 388ed15e82
Update ValidationRule message type (#3163) 2020-11-13 11:08:27 +08:00
xrkffgg d552a41e96
fix: auto-complete disabled bg (#3143) 2020-11-12 15:53:19 +08:00
tangjinzhou c57df7db0c bump 1.7.2 2020-11-06 22:19:21 +08:00
tangjinzhou bb8bf0e0f8 test: update snap 2020-11-06 22:13:45 +08:00
tangjinzhou 1d2b93c871 fix: textarea height not correct #2974 2020-11-06 21:25:45 +08:00
tanjinzhou ee0470c280 revert: menu to 1.6.5 #3112 2020-11-06 16:44:30 +08:00
tangjinzhou aa1c9b237e fix: tree-select throw error #3126 2020-11-05 22:49:14 +08:00
tangjinzhou 1aca897b97 bump 1.7.1 2020-10-28 23:16:59 +08:00
tangjinzhou 5eb57fb1a9 fix: Menu component, wrong display Tooltip prompt problem 2020-10-28 23:16:41 +08:00
tanjinzhou a60ba677c2 bump 1.7.0 2020-10-28 13:27:32 +08:00
dogrod f194973151
fix(Table): Fix checkbox does not work when Table Filter value is number type (#3052) 2020-10-28 11:36:06 +08:00
tanjinzhou ef9797d337 style: prettier code 2020-10-28 11:32:38 +08:00
tanjinzhou ce1148838b feat: menu support nest component 2020-10-28 11:31:32 +08:00
tanjinzhou dae751368b fix: table ellipsis not work at fixed column #2916 #3021 2020-10-27 16:13:13 +08:00
tanjinzhou 5597ec0a91 fix: auto-complete select tab focus logic #1438 #3015 2020-10-27 14:57:47 +08:00
tanjinzhou f26c0218d5 feat: support webpack5 2020-10-27 14:03:43 +08:00
tanjinzhou aed1ff0660 perf: update some less 2020-10-27 14:03:25 +08:00
tanjinzhou a43b128262 feat: add ga_IE locale 2020-10-27 14:02:40 +08:00
John60676 6c521620b6
fix(modal): title props support render function (#3030) 2020-10-24 23:33:24 +08:00
Sun 4a3e310db7
fix: space can not inherit attrs (#2902) 2020-09-29 18:28:24 +08:00
tanjinzhou 5c8b77957c fix: upload method not work #2837 2020-09-23 14:21:10 +08:00
tanjinzhou 346a5ce2ba fix: modal types error #2790 2020-09-23 14:20:12 +08:00
Fei Teng 4851d10f60
fix bug tree select custom slot cann't use custom name (#2827) 2020-09-17 16:33:47 +08:00
Emmanuel Akhigbe 6e35cec375
Update dropdown.d.ts (#2757)
Correct typo; 'ontainer' to 'container'
2020-08-27 14:46:02 +08:00
tanjinzhou b690b38b7e test: update snap 2020-08-25 16:34:50 +08:00
tanjinzhou ab7bb9068b release 1.6.5 2020-08-25 16:11:18 +08:00
4911 changed files with 194735 additions and 595809 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,
};

14
.babelrc Normal file
View File

@ -0,0 +1,14 @@
{
"env": {
"test": {
"presets": [["env", { "targets": { "node": "current" } }]],
"plugins": [
"transform-vue-jsx",
"transform-object-assign",
"transform-object-rest-spread",
"transform-class-properties",
"transform-runtime"
]
}
}
}

View File

@ -7,7 +7,3 @@ es/
lib/
_site/
dist/
site/dist/
components/version/version.ts
site/src/router/demoRoutes.js
locale/

53
.eslintrc Normal file
View File

@ -0,0 +1,53 @@
{
"root": true,
"env": {
"browser": true,
"node": true,
"jasmine": true,
"jest": true,
"es6": true
},
"parserOptions": {
"parser": "babel-eslint"
},
"extends": ["plugin:vue/recommended", "prettier"],
"plugins": ["markdown"],
"overrides": [
{
"files": ["**/demo/*.md"],
"processor": "markdown/markdown",
"rules": {
"no-console": "off"
}
}
],
"rules": {
"comma-dangle": [2, "always-multiline"],
"no-var": "error",
"no-console": [2, { "allow": ["warn", "error"] }],
"object-shorthand": 2,
"no-unused-vars": [2, { "ignoreRestSiblings": true, "argsIgnorePattern": "^h$" }],
"no-undef": 2,
"camelcase": "off",
"no-extra-boolean-cast": "off",
"semi": ["error", "always"],
"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/max-attributes-per-line": [
2,
{
"singleline": 20,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}
]
},
"globals": {
"h": true
}
}

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',
},
};

1
.gitattributes vendored
View File

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

7
.github/FUNDING.yml vendored
View File

@ -3,3 +3,10 @@
github: # [tangjinzhou]
open_collective: ant-design-vue
patreon: tangjinzhou
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom:
[
"https://www.paypal.me/tangjinzhou",
"https://www.buymeacoffee.com/antdv"
]

View File

@ -1,4 +1,4 @@
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: Create new issue
url: https://vuecomponent.github.io/issue-helper/

51
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,51 @@
First of all, thank you for your contribution! 😄
New feature please send pull request to feature branch, and rest to master branch. Pull request will be merged after one of collaborators approve. Please makes sure that these form are filled before submitting your pull request, thank you!
[[中文版模板 / Chinese template](https://github.com/vueComponent/ant-design-vue/blob/master/.github/PULL_REQUEST_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,8 +1,8 @@
首先,感谢你的贡献! 😄
新特性请提交至 feature 分支,其余可提交至 main 分支。在一个维护者审核通过后合并。请确保填写以下 pull request 的信息,谢谢!~
新特性请提交至 feature 分支,其余可提交至 master 分支。在一个维护者审核通过后合并。请确保填写以下 pull request 的信息,谢谢!~
[[English Template / 英文模板](./pr_en.md)]
[[English Template / 英文模板](?expand=1)]
### 这个变动的性质是

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,7 +1,7 @@
name: Build and Deploy to Cloudflare
on:
push:
branches: [ main ]
branches: [ 1.x ]
jobs:
build:
@ -20,17 +20,22 @@ jobs:
with:
node-version: 20
- name: Install dependencies
- name: Install root dependencies
run: npm install --force
- name: Install antdv-demo dependencies
working-directory: antdv-demo
run: npm install --force
- name: Build application
working-directory: antdv-demo
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-files
path: site/dist/
path: antdv-demo/_site/
retention-days: 1
deploy:
@ -52,7 +57,7 @@ jobs:
uses: actions/download-artifact@v4
with:
name: build-files
path: site/dist/
path: antdv-demo/_site/
- name: Deploy (Workers + Static Assets)
uses: cloudflare/wrangler-action@v3.14.1

View File

@ -10,13 +10,13 @@ jobs:
uses: actions/checkout@v2
- name: cache package-lock.json
uses: actions/cache@v4
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
run: npm i --package-lock-only
- name: hack for singe file
run: |
@ -27,7 +27,7 @@ jobs:
- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
@ -41,24 +41,17 @@ jobs:
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
with:
token: ${{ secrets.ACCESS_TOKEN }}
- name: restore cache from package-lock.json
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}

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,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

@ -10,13 +10,13 @@ jobs:
uses: actions/checkout@v2
- name: cache package-lock.json
uses: actions/cache@v4
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
run: npm i --package-lock-only
- name: hack for singe file
run: |
@ -27,7 +27,7 @@ jobs:
- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
@ -43,25 +43,25 @@ jobs:
uses: actions/checkout@v2
- name: restore cache from package-lock.json
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
- name: cache lib
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: lib
key: lib-${{ github.sha }}
- name: cache es
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: es
key: es-${{ github.sha }}
@ -77,13 +77,13 @@ jobs:
uses: actions/checkout@v2
- name: restore cache from package-lock.json
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
@ -99,13 +99,13 @@ jobs:
uses: actions/checkout@v2
- name: restore cache from package-lock.json
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
uses: actions/cache@v4
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}

18
.gitignore vendored
View File

@ -36,6 +36,9 @@ build/Release
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
@ -59,11 +62,9 @@ jspm_packages/
dist
lib
es
/locale
_site
yarn.lock
package-lock.json
pnpm-lock.yaml
/coverage
# 备份文件
@ -71,16 +72,5 @@ pnpm-lock.yaml
list.txt
site/dev.js
# IDE 语法提示临时文件
v2-doc/
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

@ -2,59 +2,42 @@ 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)/',
'node_modules/[^/]+?/(?!(es|node_modules)/)', // Ignore modules without es dir
];
const testPathIgnorePatterns = ['/node_modules/', 'node'];
function getTestRegex(libDir) {
if (libDir === 'dist') {
return 'demo\\.test\\.js$';
}
return '.*\\.test\\.(j|t)sx?$';
}
module.exports = {
verbose: true,
testURL: 'http://localhost/',
setupFiles: ['./tests/setup.js'],
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'vue', 'md', 'jpg'],
moduleFileExtensions: ['js', 'jsx', 'json', 'vue', 'md', 'jpg'],
modulePathIgnorePatterns: ['/_site/'],
testPathIgnorePatterns: testPathIgnorePatterns,
testPathIgnorePatterns: ['/node_modules/', 'node'],
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',
'.*\\.(vue|md)$': '<rootDir>/node_modules/vue-jest',
'^.+\\.(js|jsx)$': '<rootDir>/node_modules/babel-jest',
'^.+\\.svg$': '<rootDir>/node_modules/jest-transform-stub',
},
testRegex: getTestRegex(libDir),
testRegex: libDir === 'dist' ? 'demo\\.test\\.js$' : '.*\\.test\\.js$',
moduleNameMapper: {
'^@/(.*)$/': '<rootDir>/$1',
'^ant-design-vue$': '<rootDir>/components/index',
'^ant-design-vue/es/(.*)$': '<rootDir>/components/$1',
'^@/(.*)$': '<rootDir>/$1',
'ant-design-vue$': '<rootDir>/components/index.js',
'ant-design-vue/es': '<rootDir>/components',
'^vue$': 'vue/dist/vue.common.js',
},
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
collectCoverage: process.env.COVERAGE === 'true',
collectCoverageFrom: [
'components/**/*.{js,jsx,vue}',
'!components/*/style/index.{js,jsx}',
'!components/style/*.{js,jsx}',
'!components/*/locale/*.{js,jsx}',
'!components/*/__tests__/**/type.{js,jsx}',
'!components/vc-*/**/*',
'!components/*/demo/**/*',
'!components/_util/**/*',
'!components/align/**/*',
'!components/trigger/**/*',
'!components/style.js',
'!**/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

@ -18,6 +18,7 @@ yarn-error.log
.editorconfig
.eslintignore
**/*.yml
components/style/color/*.less
**/assets
.gitattributes
.stylelintrc
@ -27,5 +28,4 @@ yarn-error.log
.huskyrc
.gitmodules
*.png
v2-doc/

View File

@ -1,11 +1,8 @@
{
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"printWidth": 100,
"proseWrap": "never",
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"overrides": [
{
"files": ".prettierrc",

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
}
}

3
.vcmrc
View File

@ -9,8 +9,7 @@
"perf",
"test",
"chore",
"revert",
"ci"
"revert"
],
"warnOnFail": false,
"autoFix": false

View File

@ -24,7 +24,6 @@
<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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

22
LICENSE
View File

@ -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,49 +1,56 @@
<p align="center">
<a href="https://www.antdv.com/">
<img width="200" src="https://www.antdv.com/logo.png">
</a>
</p>
<h1 align="center">
<a href="https://www.antdv.com/" target="_blank">Ant Design Vue</a>
</h1>
<div align="center">
基于 Ant Design 和 Vue 3 的企业级 UI 组件库。
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)
![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) [![Join the chat at https://gitter.im/vueComponent/ant-design-english](https://badges.gitter.im/vueComponent/ant-design-english.svg?style=flat-square)](https://gitter.im/vueComponent/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) (English) [![Join the chat at https://gitter.im/vueComponent/ant-design-vue](https://img.shields.io/gitter/room/vueComponent/ant-design-vue.svg?style=flat-square)](https://gitter.im/vueComponent/ant-design-vue?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)(中文) [![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)
</div>
[![](https://cdn-images-1.medium.com/max/2000/1*NIlj0-TdLMbo_hzSBP8tmg.png)](https://www.antdv.com/)
<div align="center">
<sup><strong>赞助商</strong></sup>
<br>
<a href="https://mentorbook.ai/" target="_blank">
<img src="/site/public/mentorbook_banner_zh.svg" alt="Mentorbook.AI - 你的 AI 导师,你的学习之旅" />
</a>
</div>
[English](./README.md) | 简体中文
<p align="center">
<b>Special thanks to the generous sponsorship by:</b>
</p>
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://tipe.io/?ref=ant-design-vue" target="_blank">
<img width="120px" src="https://user-images.githubusercontent.com/1016365/34124854-48fafa06-e3e9-11e7-8c04-251055feebee.png">
</a>
</td>
</tr>
</tbody>
</table>
## 特性
- 提炼自企业级中后台产品的交互语言和视觉风格。
- 开箱即用的高质量 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)
- 从 [2.x](https://2x.antdv.com/) 版本开始支持 Vue 3
## 支持环境
- 现代浏览器。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性)
- 现代浏览器和 IE9 及以上(需要 [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 |
| IE9, IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 安装
@ -74,8 +81,6 @@ $ yarn add ant-design-vue
| [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 界面解决方案 |
## 问答
@ -90,32 +95,23 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
- [Patreon](https://www.patreon.com/tangjinzhou)
- [opencollective](https://opencollective.com/ant-design-vue)
- [paypal](https://www.paypal.me/tangjinzhou)
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
## 赞助商
## Sponsors
成为赞助商,并在 Github 上的自述文件上获得您的徽标,并链接到您的网站。 [[成为赞助商](https://opencollective.com/ant-design-vue#sponsor)]
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://www.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>
<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>
## 支持者
## Backers
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://opencollective.com/ant-design-vue#backer)]
Support us with a monthly donation and help us continue our activities. [[Become a backer](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>
<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)]
Support us with a monthly donation and help us continue our activities. [[Become a backer](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

@ -12,48 +12,49 @@
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)
![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) [![Join the chat at https://gitter.im/vueComponent/ant-design-english](https://badges.gitter.im/vueComponent/ant-design-english.svg?style=flat-square)](https://gitter.im/vueComponent/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) (English) [![Join the chat at https://gitter.im/vueComponent/ant-design-vue](https://img.shields.io/gitter/room/vueComponent/ant-design-vue.svg?style=flat-square)](https://gitter.im/vueComponent/ant-design-vue?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)(中文) [![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)
</div>
[![](https://cdn-images-1.medium.com/max/2000/1*NIlj0-TdLMbo_hzSBP8tmg.png)](https://www.antdv.com/)
<div align="center">
<sup><strong>Sponsored by</strong></sup>
<br>
<a href="https://mentorbook.ai/" target="_blank">
<img src="/site/public/mentorbook_banner_en.svg" alt="Mentorbook.AI - Your AI Mentor, Your Learning Journey" />
</a>
</div>
English | [简体中文](./README-zh_CN.md)
<p align="center">
<b>Special thanks to the generous sponsorship by:</b>
</p>
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://tipe.io/?ref=ant-design-vue" target="_blank">
<img width="120px" src="https://user-images.githubusercontent.com/1016365/34124854-48fafa06-e3e9-11e7-8c04-251055feebee.png">
</a>
</td>
</tr>
</tbody>
</table>
## Features
- An enterprise-class UI design system for desktop applications.
- A set of high-quality Vue 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)
- Support Vue 3 from [2.x](https://2x.antdv.com/)
## Environment Support
- Modern browsers. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#compatibility))
- Modern browsers and 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 |
| IE9, IE10, IE11, 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
@ -63,7 +64,7 @@ $ npm install ant-design-vue --save
$ yarn add ant-design-vue
```
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
@ -80,8 +81,6 @@ If you are in a bad network environment, you can try other registries and tools
| [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
@ -90,24 +89,25 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette
- [Patreon](https://www.patreon.com/tangjinzhou)
- [opencollective](https://opencollective.com/ant-design-vue)
- [paypal](https://www.paypal.me/tangjinzhou)
- 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://www.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>
<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>
## Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ant-design-vue#backer)]
<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><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>
## Patreon
Support us with a monthly donation and help us continue our activities. [[Become a backer](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>
## [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

@ -3,6 +3,7 @@
'use strict';
require('colorful').colorful();
require('colorful').isatty = true;
const program = require('commander');
const packageInfo = require('../../package.json');

View File

@ -1,14 +1,12 @@
#!/usr/bin/env node
/* eslint-disable no-console */
'use strict';
require('colorful').colorful();
require('colorful').isatty = true;
const gulp = require('gulp');
const program = require('commander');
program.option('-c --npm-tag <type>', 'add --npm-tag=xxx');
program.on('--help', () => {
console.log(' Usage:'.to.bold.blue.color);
console.log();

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,48 +1,36 @@
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-inline-import-data-uri'),
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'),
require.resolve('babel-plugin-transform-class-properties'),
];
plugins.push([
require.resolve('babel-plugin-transform-runtime'),
{
polyfill: false,
},
]);
return {
presets: [
[
resolve('@babel/preset-env'),
require.resolve('babel-preset-env'),
{
modules,
targets: isThereHaveBrowserslistConfig()
? undefined
: {
browsers: ['last 2 versions', 'Firefox ESR', '> 1%', 'ie >= 11'],
targets: {
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4',
],
},
},
],
@ -50,7 +38,7 @@ module.exports = function (modules) {
plugins,
env: {
test: {
plugins: [resolve('babel-plugin-istanbul')],
plugins: [require.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,14 +1,13 @@
const { getProjectPath, resolve } = require('./utils/projectHelper');
const path = require('path');
const webpack = require('webpack');
const WebpackBar = require('webpackbar');
const { merge } = require('webpack-merge');
const webpackMerge = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const postcssConfig = require('./postcssConfig');
const CleanUpStatsPlugin = require('./utils/CleanUpStatsPlugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const distFileBaseName = 'antd';
@ -22,49 +21,41 @@ const imageOptions = {
limit: 10000,
};
function getWebpackConfig(modules, esm = false) {
const pkg = require(getProjectPath('package.json'));
function getWebpackConfig(modules) {
const pkg = require(path.join(process.cwd(), 'package.json'));
const babelConfig = require('./getBabelCommonConfig')(modules || false);
const pluginImportOptions = {
const pluginImportOptions = [
{
style: true,
libraryName: distFileBaseName,
libraryDirectory: 'components',
};
babelConfig.plugins.push([resolve('babel-plugin-import'), pluginImportOptions]);
},
];
babelConfig.plugins.push([require.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: [
},
node: [
'child_process',
'cluster',
'dgram',
@ -76,9 +67,9 @@ function getWebpackConfig(modules, esm = false) {
'repl',
'tls',
].reduce((acc, name) => Object.assign({}, acc, { [name]: 'empty' }), {}),
},
module: {
noParse: [/moment.js/],
rules: [
{
test: /\.vue$/,
@ -92,14 +83,8 @@ function getWebpackConfig(modules, esm = false) {
{
loader: 'babel-loader',
options: {
presets: [resolve('@babel/preset-env')],
plugins: [
[
resolve('@vue/babel-plugin-jsx'),
{ mergeProps: false, enableObjectSlots: false },
],
resolve('@babel/plugin-proposal-object-rest-spread'),
],
presets: ['env'],
plugins: ['transform-vue-jsx', 'transform-object-rest-spread'],
},
},
],
@ -114,21 +99,6 @@ function getWebpackConfig(modules, esm = false) {
exclude: /node_modules/,
options: babelConfig,
},
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
options: babelConfig,
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
},
{
test: /\.css$/,
use: [
@ -141,13 +111,33 @@ function getWebpackConfig(modules, esm = false) {
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer'],
options: Object.assign({}, postcssConfig, { sourceMap: true }),
},
],
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: Object.assign({}, postcssConfig, { sourceMap: true }),
},
{
loader: 'less-loader',
options: {
lessOptions: {
sourceMap: true,
javascriptEnabled: true,
},
},
},
],
},
// Images
@ -165,12 +155,11 @@ function getWebpackConfig(modules, esm = false) {
},
plugins: [
// new BundleAnalyzerPlugin(),
new CaseSensitivePathsPlugin(),
new webpack.BannerPlugin(`
${pkg.name} v${pkg.version}
Copyright 2017-present, Ant Design Vue.
Copyright 2017-present, ant-design-vue.
All rights reserved.
`),
new WebpackBar({
@ -179,57 +168,32 @@ All rights reserved.
}),
new CleanUpStatsPlugin(),
],
performance: {
hints: false,
},
};
if (process.env.RUN_ENV === 'PRODUCTION') {
let entry = ['./index'];
config.externals = [
{
const 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.output.libraryTarget = 'umd';
config.optimization = {
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
warnings: false,
},
sourceMap: true,
}),
],
};
// Development
const uncompressedConfig = merge({}, config, {
const uncompressedConfig = webpackMerge({}, config, {
entry: {
[entryName]: entry,
[distFileBaseName]: entry,
},
mode: 'development',
plugins: [
@ -240,12 +204,13 @@ All rights reserved.
});
// Production
const prodConfig = merge({}, config, {
const prodConfig = webpackMerge({}, config, {
entry: {
[`${entryName}.min`]: entry,
[`${distFileBaseName}.min`]: entry,
},
mode: 'production',
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
@ -254,15 +219,14 @@ All rights reserved.
}),
],
optimization: {
minimize: true,
minimizer: [new CssMinimizerPlugin({})],
minimizer: [new OptimizeCSSAssetsPlugin({})],
},
});
return [prodConfig, uncompressedConfig];
}
return [config];
return config;
}
getWebpackConfig.webpack = webpack;

View File

@ -1,15 +1,19 @@
/* eslint-disable no-console */
const { getProjectPath, getConfig } = require('./utils/projectHelper');
'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 { Octokit } = require('@octokit/rest');
const packageJson = require(`${process.cwd()}/package.json`);
// const getNpm = require('./getNpm')
// const selfPackage = require('../package.json')
const chalk = require('chalk');
@ -17,35 +21,21 @@ const getNpmArgs = require('./utils/get-npm-args');
const getChangelog = require('./utils/getChangelog');
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 replaceLib = require('./replaceLib');
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 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 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;`;
const libDir = path.join(cwd, 'lib');
const esDir = path.join(cwd, 'es');
function dist(done) {
rimraf.sync(path.join(cwd, 'dist'));
process.env.RUN_ENV = 'PRODUCTION';
const webpackConfig = require(getProjectPath('webpack.build.conf.js'));
const webpackConfig = require(path.join(cwd, 'webpack.build.conf.js'));
webpack(webpackConfig, (err, stats) => {
if (err) {
console.error(err.stack || err);
@ -56,17 +46,11 @@ function dist(done) {
}
const info = stats.toJson();
const { dist: { finalize } = {}, bail } = getConfig();
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);
}
@ -81,44 +65,10 @@ function dist(done) {
version: false,
});
console.log(buildInfo);
// Additional process of dist finalize
if (finalize) {
console.log('[Dist] Finalization...');
finalize();
}
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;
@ -126,122 +76,67 @@ function babelify(js, modules) {
if (modules === false) {
babelConfig.plugins.push(replaceLib);
}
const stream = js.pipe(babel(babelConfig)).pipe(
let stream = js.pipe(babel(babelConfig)).pipe(
through2.obj(function z(file, encoding, next) {
this.push(file.clone());
if (modules !== false) {
if (file.path.match(/\/style\/index\.(js|jsx)$/)) {
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'),
content.replace(/\/style\/?'/g, "/style/css'").replace(/\.less/g, '.css'),
);
file.path = file.path.replace(/index\.(js|jsx)$/, 'css.js');
this.push(file);
}
next();
} else {
next();
}
}),
);
return stream.pipe(gulp.dest(modules === false ? esDir : libDir));
}
function compile(modules) {
const { compile: { transformTSFile, transformFile } = {} } = getConfig();
rimraf.sync(modules !== false ? libDir : esDir);
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(
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));
}
if (transformTSFile) {
sourceStream = sourceStream.pipe(
function compile(modules) {
rimraf.sync(modules !== false ? libDir : esDir);
const less = gulp
.src(['components/**/*.less'])
.pipe(
through2.obj(function(file, encoding, next) {
let nextFile = transformTSFile(file) || file;
nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
nextFile.forEach(f => this.push(f));
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();
}),
);
}
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));
}
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);
}
})
.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 source = ['components/**/*.js', 'components/**/*.jsx', '!components/*/__tests__/*'];
const jsFilesStream = babelify(gulp.src(source), modules);
return merge2([less, jsFilesStream, assets]);
}
function tag() {
@ -347,6 +242,11 @@ function publish(tagString, done) {
}
function pub(done) {
dist(code => {
if (code) {
done(code);
return;
}
const notOk = !packageJson.version.match(/^\d+\.\d+\.\d+$/);
let tagString;
if (argv['npm-tag']) {
@ -366,52 +266,37 @@ function pub(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();
}
gulp.task(
'compile-with-es',
gulp.series(done => {
compile(false).on('finish', function() {
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');
gulp.series('compile-with-es', done => {
compile().on('finish', function() {
done();
});
}),
);
gulp.task(
'dist',
gulp.series(done => {
gulp.series('compile', done => {
dist(done);
}),
);
gulp.task(
'pub',
gulp.series('check-git', 'compile', 'dist', done => {
gulp.series('check-git', 'compile', done => {
// if (!process.env.GITHUB_TOKEN) {
// console.log('no GitHub token found, skip');
// } else {
@ -452,7 +337,7 @@ gulp.task(
newVersion.trim() === version
) {
// eslint-disable-next-line no-unused-vars
runCmd('npm', ['run', 'pub'], _code => {
runCmd('npm', ['run', 'pub'], code => {
done();
});
} else {
@ -475,11 +360,7 @@ gulp.task(
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
) {
if (/^pu(b(l(i(sh?)?)?)?)?$/.test(arg) && npmArgs.indexOf('--with-antd-tools') < 0) {
reportError();
done(1);
return;
@ -489,11 +370,3 @@ gulp.task(
done();
}),
);
gulp.task(
'sort-api-table',
gulp.series(done => {
sortApiTable();
done();
}),
);

View File

@ -0,0 +1,6 @@
const rucksack = require('rucksack-css');
const autoprefixer = require('autoprefixer');
module.exports = {
plugins: [rucksack(), autoprefixer()],
};

View File

@ -1,26 +1,14 @@
'use strict';
const { dirname } = require('path');
const { join, dirname } = require('path');
const fs = require('fs');
const { getProjectPath } = require('./utils/projectHelper');
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));
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));
const esPath = dirname(join(cwd, `node_modules/${esModule}`));
if (fs.existsSync(esPath)) {
path.node.source.value = esModule;
}

View File

@ -1,17 +1,9 @@
'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 runner = require('child_process').spawn(cmd, args, {
// keep color
stdio: 'inherit',

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: '~' })],
javascriptEnabled: true,
};
return less
.render(data, lessOpts)
.then(result => {
const source = result.css;
return postcss(postcssConfig.plugins).process(source, { from: undefined });
})
.then(r => {
return r.css;
});
}
module.exports = transformLess;

View File

@ -24,13 +24,13 @@ class CleanUpStatsPlugin {
apply(compiler) {
compiler.hooks.done.tap('CleanUpStatsPlugin', stats => {
const { children, warnings } = stats.compilation;
const { children } = 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));
}
// if (Array.isArray(warnings)) {
// stats.compilation.warnings = warnings.filter(message => this.shouldPickWarning(message));
// }
});
}
}

View File

@ -2,11 +2,6 @@
// 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;
try {

View File

@ -1,7 +1,10 @@
const fs = require('fs');
module.exports = function getChangelog(file, version) {
const lines = fs.readFileSync(file).toString().split('\n');
const lines = fs
.readFileSync(file)
.toString()
.split('\n');
const changeLog = [];
const startPattern = new RegExp(`^## ${version}`);
const stopPattern = /^## /; // 前一个版本

View File

@ -1,7 +1,6 @@
'use strict';
const path = require('path');
const isWindows = require('is-windows');
module.exports = function getRunCmdEnv() {
const env = {};
@ -12,12 +11,16 @@ module.exports = function getRunCmdEnv() {
const nodeModulesBinDir = path.join(__dirname, '../../node_modules/.bin');
Object.entries(env)
.filter(v => v.slice(0, 1).pop().toLowerCase() === 'path')
.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;
env[key] = env[key] ? `${nodeModulesBinDir}:${env[key]}` : 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,
};

14
antdv-demo/.babelrc Normal file
View File

@ -0,0 +1,14 @@
{
"env": {
"test": {
"presets": [["env", { "targets": { "node": "current" } }]],
"plugins": [
"transform-vue-jsx",
"transform-object-assign",
"transform-object-rest-spread",
"transform-class-properties",
"transform-runtime"
]
}
}
}

11
antdv-demo/.editorconfig Normal file
View File

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

8
antdv-demo/.eslintignore Normal file
View File

@ -0,0 +1,8 @@
node_modules/
**/*.spec.*
**/style/
*.html
/components/test/*
_site/
dist/
package.json

53
antdv-demo/.eslintrc Normal file
View File

@ -0,0 +1,53 @@
{
"root": true,
"env": {
"browser": true,
"node": true,
"jasmine": true,
"jest": true,
"es6": true
},
"parserOptions": {
"parser": "babel-eslint"
},
"extends": ["plugin:vue/recommended", "prettier"],
"plugins": ["markdown"],
"overrides": [
{
"files": ["**/demo/*.md"],
"processor": "markdown/markdown",
"rules": {
"no-console": "off"
}
}
],
"rules": {
"comma-dangle": [2, "always-multiline"],
"no-var": "error",
"no-console": [2, { "allow": ["warn", "error"] }],
"object-shorthand": 2,
"no-unused-vars": [2, { "ignoreRestSiblings": true, "argsIgnorePattern": "^h$" }],
"no-undef": 2,
"camelcase": "off",
"no-extra-boolean-cast": "off",
"semi": ["error", "always"],
"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/max-attributes-per-line": [
2,
{
"singleline": 20,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}
]
},
"globals": {
"h": true
}
}

109
antdv-demo/.gitignore vendored Normal file
View File

@ -0,0 +1,109 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
site/dev.js
_site/
package-lock.json
testDemo/

7
antdv-demo/.huskyrc Normal file
View File

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

View File

@ -0,0 +1,29 @@
**/*.svg
package.json
lib/
es/
dist/
_site/
coverage/
CNAME
LICENSE
yarn.lock
netlify.toml
yarn-error.log
*.sh
*.snap
.gitignore
.npmignore
.prettierignore
.DS_Store
.editorconfig
.eslintignore
**/*.yml
components/style/color/*.less
**/assets
.gitattributes
.stylelintrc
.vcmrc
.png
.npmrc.template
.huskyrc

14
antdv-demo/.prettierrc Normal file
View File

@ -0,0 +1,14 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"proseWrap": "never",
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
]
}

23
antdv-demo/.stylelintrc Normal file
View File

@ -0,0 +1,23 @@
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
"rules": {
"comment-empty-line-before": null,
"declaration-empty-line-before": null,
"function-comma-newline-after": null,
"function-name-case": null,
"function-parentheses-newline-inside": null,
"function-max-empty-lines": null,
"function-whitespace-after": null,
"indentation": null,
"number-leading-zero": null,
"number-no-trailing-zeros": null,
"rule-empty-line-before": null,
"selector-combinator-space-after": null,
"selector-list-comma-newline-after": null,
"selector-pseudo-element-colon-notation": null,
"unit-no-unknown": null,
"value-list-max-empty-lines": null,
"font-family-no-missing-generic-family-keyword": null,
"no-descending-specificity": null
}
}

View File

@ -0,0 +1,3 @@
module.exports = {
...require('./mock/user'),
};

5
antdv-demo/build.sh Normal file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
rm -rf dist
mkdir dist
./node_modules/.bin/webpack --config webpack.site.config.js
cp dist/index.html index.html

View File

@ -0,0 +1,5 @@
module.exports = {
dev: {
componentName: 'form', // dev components
},
};

213
antdv-demo/build/dev.js Normal file
View File

@ -0,0 +1,213 @@
process.env.ENTRY_INDEX = 'dev';
const fs = require('fs');
const path = require('path');
const chokidar = require('chokidar');
const importFresh = require('import-fresh');
const replace = require('json-templater/string');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const devWebpack = require('./webpack.dev.conf');
const configPath = path.join(__dirname, './config.js');
/**
* a-bc-d --> aBcD
* @param {string} s
*/
const camelize = s => s.replace(/-(\w)/g, ($, $1) => $1.toUpperCase());
/**
* radio-group --> radio
* @param {string} s
*/
const getUpper = s => s.replace(/(-[a-z]*)/g, '');
let { componentName } = require('./config').dev;
const componentsInPrototype = ['Modal', 'message', 'notification'];
const MAIN_TEMPLATE = `import 'babel-polyfill';
import Vue from 'vue';
import Vuex from 'vuex';
import VueI18n from 'vue-i18n';
import VueRouter from 'vue-router';
import VueClipboard from 'vue-clipboard2';
import Md from '../components/md';
import Api from '../components/api';
import demoBox from '../components/demoBox';
import demoSort from '../components/demoSort';
import demoContainer from '../components/demoContainer';
import { message, notification } from 'ant-design-vue';
{{importComponents}}
{{importStyles}}
import 'ant-design-vue/es/message/style';
import 'ant-design-vue/es/notification/style';
import Test from '../docs/{{name}}/demo/index.vue';
import zhCN from '../theme/zh-CN';
import enUS from '../theme/en-US';
import './index.less';
Vue.use(Vuex);
Vue.use(VueClipboard);
Vue.use(VueRouter);
Vue.use(VueI18n);
Vue.component(Md.name, Md);
Vue.component(Api.name, Api);
Vue.component('demo-box', demoBox);
Vue.component('demo-sort', demoSort);
Vue.component('demo-container', demoContainer);
Vue.prototype.$message = message;
Vue.prototype.$notification = notification;
Vue.prototype.$info = Modal.info;
Vue.prototype.$success = Modal.success;
Vue.prototype.$error = Modal.error;
Vue.prototype.$warning = Modal.warning;
Vue.prototype.$confirm = Modal.confirm;
Vue.prototype.$destroyAll = Modal.destroyAll;
Vue.prototype.$form = Form;
Vue.use(Modal);
{{install}}
const i18n = new VueI18n({
locale: enUS.locale,
messages: {
[enUS.locale]: { message: enUS.messages },
[zhCN.locale]: { message: zhCN.messages },
},
});
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/test',
component: () => import('../testDemo/index.vue'),
}, {
path: '/*', component: Test
}],
});
const store = new Vuex.Store({
state: {
username: 'zeka',
},
mutations: {
update(state, payload) {
state.username = payload.username;
},
},
});
new Vue({
el: '#app',
i18n,
router,
store,
});
`;
const OUTPUT_PATH = path.join(__dirname, '../site/dev.js');
const generateEntry = components =>
Object.keys(components)
.map(component => `import ${component} from 'ant-design-vue/es/${components[component]}';`)
.join('\n');
const generateStyles = components =>
Object.keys(components)
.map(component => `import 'ant-design-vue/es/${components[component]}/style';`)
.join('\n');
const generateInstall = components =>
Object.keys(components)
.map(component => `Vue.use(${component});`)
.join('\n');
const renderTemplate = name => {
const components = {
Tooltip: 'tooltip', // for DemoBox
Icon: 'icon', // Basic
Form: 'form',
Modal: 'modal',
};
const demoPaths = fs
.readdirSync(path.join(__dirname, `../docs/${name}/demo`))
.map(p => `../docs/${name}/demo/${p}`);
const testPaths = fs
.readdirSync(path.join(__dirname, `../testDemo`))
.map(p => `../testDemo/${p}`);
[...demoPaths, ...testPaths].forEach(demoPath => {
const demo = fs.readFileSync(path.join(__dirname, demoPath)).toString();
const componentsInDemo = demo.match(/a-(\w+(-\w+)*)/g) || [];
componentsInDemo.forEach(name => {
const dirName = name.replace(/^a-/, '');
const componentName = camelize(name).replace(/^a/, '');
const upperComponentDir = getUpper(dirName);
const upperComponentName = upperComponentDir.replace(/^[a-z]/, $ => $.toUpperCase());
const componentPath = path.join(__dirname, `../../components/${dirName}`);
if (fs.existsSync(componentPath)) {
if (componentsInPrototype.includes(componentName)) {
return;
}
components[componentName] = dirName;
} else if (fs.existsSync(path.join(__dirname, `../../components/${upperComponentDir}`))) {
components[upperComponentName] = upperComponentDir;
}
});
});
const importComponents = generateEntry(components);
const importStyles = generateStyles(components);
const install = generateInstall(components);
const template = replace(MAIN_TEMPLATE, {
importComponents,
importStyles,
install,
name,
});
fs.writeFileSync(OUTPUT_PATH, template);
};
function fsExistsSync(path) {
try {
fs.accessSync(path, fs.F_OK);
} catch (e) {
return false;
}
return true;
}
if (!fsExistsSync(path.join(__dirname, '../testDemo/index.vue'))) {
if (!fsExistsSync(path.join(__dirname, '../testDemo'))) {
fs.mkdirSync(path.join(__dirname, '../testDemo'));
}
fs.writeFileSync(path.join(__dirname, '../testDemo/index.vue'), `<template></template>`);
}
let demoWatcher;
chokidar.watch(configPath, { ignoreInitial: true }).on('change', async () => {
({ componentName } = importFresh(configPath).dev);
demoWatcher && (await demoWatcher.close());
demoWatcher = chokidar.watch(path.join(__dirname, `../docs/${componentName}/demo`));
demoWatcher.on('change', () => {
renderTemplate(componentName);
});
renderTemplate(componentName);
});
renderTemplate(componentName);
const compiler = webpack(devWebpack);
const configuration = devWebpack.devServer;
const server = new WebpackDevServer(compiler, configuration);
server.listen(configuration.port);

View File

@ -0,0 +1,45 @@
'use strict';
module.exports = function(modules) {
const plugins = [
require.resolve('babel-plugin-transform-vue-jsx'),
require.resolve('babel-plugin-inline-import-data-uri'),
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'),
require.resolve('babel-plugin-transform-class-properties'),
];
plugins.push([
require.resolve('babel-plugin-transform-runtime'),
{
polyfill: false,
},
]);
return {
presets: [
[
require.resolve('babel-preset-env'),
{
modules,
targets: {
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4',
],
},
},
],
],
plugins,
env: {
test: {
plugins: [require.resolve('babel-plugin-istanbul')],
},
},
};
};

View File

@ -0,0 +1,166 @@
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = function(env) {
const isDev = env === 'development';
return {
test: /\.less$/,
oneOf: [
/* config.module.rule('less').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
isDev
? {
loader: 'vue-style-loader',
options: {
sourceMap: isDev,
shadowMode: false,
},
}
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: isDev,
importLoaders: 2,
modules: {
localIdentName: '[name]_[local]_[hash:base64:5]',
},
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
sourceMap: isDev,
modifyVars: {},
javascriptEnabled: true,
},
},
},
],
},
/* config.module.rule('less').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
isDev
? {
loader: 'vue-style-loader',
options: {
sourceMap: isDev,
shadowMode: false,
},
}
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: isDev,
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
sourceMap: isDev,
modifyVars: {},
javascriptEnabled: true,
},
},
},
],
},
/* config.module.rule('less').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
isDev
? {
loader: 'vue-style-loader',
options: {
sourceMap: isDev,
shadowMode: false,
},
}
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: isDev,
importLoaders: 2,
modules: {
localIdentName: '[name]_[local]_[hash:base64:5]',
},
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
sourceMap: isDev,
modifyVars: {},
javascriptEnabled: true,
},
},
},
],
},
/* config.module.rule('less').oneOf('normal') */
{
use: [
isDev
? {
loader: 'vue-style-loader',
options: {
sourceMap: isDev,
shadowMode: false,
},
}
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: isDev,
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
sourceMap: isDev,
modifyVars: {},
javascriptEnabled: true,
},
},
},
],
},
],
};
};

View File

@ -0,0 +1,226 @@
const path = require('path');
const webpack = require('webpack');
const Prism = require('prismjs');
require('prismjs/components/prism-jsx.min.js');
require('prismjs/components/prism-bash.min.js');
require('prismjs/components/prism-json.min.js');
require('prismjs/components/prism-diff.min.js');
require('prismjs/components/prism-less.min.js');
const Token = require('markdown-it/lib/token');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const cheerio = require('cheerio');
const WebpackBar = require('webpackbar');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const getBabelCommonConfig = require('./getBabelCommonConfig');
const babelConfig = getBabelCommonConfig(false);
babelConfig.plugins.push(require.resolve('babel-plugin-syntax-dynamic-import'));
const fetch = (str, tag, scoped) => {
const $ = cheerio.load(str, {
decodeEntities: false,
xmlMode: true,
});
if (!tag) {
return str;
}
if (tag === 'style') {
return scoped
? $(`${tag}[scoped]`).html()
: $(`${tag}`)
.not(`${tag}[scoped]`)
.html();
}
return $(tag).html();
};
/**
* `{{ }}` => `<span>{{</span> <span>}}</span>`
* @param {string} str
* @return {string}
*/
const replaceDelimiters = function(str) {
return str.replace(/({{|}})/g, '<span>$1</span>');
};
/**
* renderHighlight
* @param {string} str
* @param {string} lang
*/
const renderHighlight = function(str, lang) {
if (!(lang && Prism.languages[lang])) {
return '';
}
try {
return replaceDelimiters(Prism.highlight(str, Prism.languages[lang], lang));
} catch (err) {}
};
const md = require('markdown-it')('default', {
html: true,
breaks: true,
highlight: renderHighlight,
}).use(require('markdown-it-anchor'), {
level: 2,
slugify: string =>
string
.trim()
.split(' ')
.join('-'),
permalink: true,
// renderPermalink: (slug, opts, state, permalink) => {},
permalinkClass: 'anchor',
permalinkSymbol: '#',
permalinkBefore: false,
});
// md.renderer.rules.fence = wrap(md.renderer.rules.fence)
const cnReg = new RegExp('<(cn)(?:[^<]|<)+</\\1>', 'g');
const usReg = new RegExp('<(us)(?:[^<]|<)+</\\1>', 'g');
md.core.ruler.push('update_template', function replace({ tokens }) {
let cn = '';
let us = '';
let template = '';
let script = '';
let style = '';
let scopedStyle = '';
let code = '';
let sourceCode = '';
tokens.forEach(token => {
if (token.type === 'html_block') {
if (token.content.match(cnReg)) {
cn = fetch(token.content, 'cn');
token.content = '';
}
if (token.content.match(usReg)) {
us = fetch(token.content, 'us');
token.content = '';
}
}
if (token.type === 'fence' && token.info === 'vue' && token.markup === '```') {
sourceCode = token.content;
code = '```html\n' + token.content + '```';
template = fetch(token.content, 'template');
script = fetch(token.content, 'script');
style = fetch(token.content, 'style');
scopedStyle = fetch(token.content, 'style', true);
token.content = '';
token.type = 'html_block';
}
});
if (template) {
let jsfiddle = {
us,
cn,
sourceCode: Buffer.from(sourceCode).toString('base64'),
};
jsfiddle = md.utils.escapeHtml(JSON.stringify(jsfiddle));
const codeHtml = code ? md.render(code.replace(/@/g, '__at__')).replace(/__at__/g, '@') : '';
const cnHtml = cn ? md.render(cn) : '';
let newContent = `
<template>
<demo-box :jsfiddle="${jsfiddle}">
<template slot="component">${template}</template>
<template slot="description">${cnHtml}</template>
<template slot="us-description">${us ? md.render(us) : ''}</template>
<template slot="code">${Buffer.from(codeHtml).toString('base64')}</template>
</demo-box>
</template>`;
newContent += script
? `
<script>
${script || ''}
</script>
`
: '';
newContent += style ? `<style>${style || ''}</style>` : '';
newContent += scopedStyle ? `<style scoped>${scopedStyle || ''}</style>` : '';
const t = new Token('html_block', '', 0);
t.content = newContent;
tokens.push(t);
}
});
const vueLoaderOptions = {
loaders: {
js: [
{
loader: 'babel-loader',
options: {
presets: ['env'],
plugins: ['transform-vue-jsx', 'transform-object-rest-spread'],
},
},
],
},
};
module.exports = {
mode: 'production',
entry: {
index: [`./site/${process.env.ENTRY_INDEX || 'index'}.js`],
},
module: {
rules: [
{
test: /\.md$/,
use: [
{
loader: 'vue-loader',
options: vueLoaderOptions,
},
{
loader: 'vue-antd-md-loader',
options: Object.assign(md, {
wrapper: 'div',
raw: true,
}),
},
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderOptions,
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: babelConfig,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
},
},
],
},
resolve:
process.env.NODE_ENV === 'development'
? {
modules: ['node_modules', path.join(__dirname, '../node_modules')],
extensions: ['.js', '.jsx', '.vue', '.md'],
alias: {
vue$: 'vue/dist/vue.esm.js',
'ant-design-vue$': path.join(__dirname, '../../components/index.js'),
'ant-design-vue/es': path.join(__dirname, '../../components'),
'ant-design-vue/lib': path.join(__dirname, '../../components'),
},
}
: {
modules: ['node_modules'],
extensions: ['.js', '.jsx', '.vue', '.md'],
alias: {
vue$: 'vue/dist/vue.esm.js',
},
},
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new VueLoaderPlugin(),
new WebpackBar(),
new HardSourceWebpackPlugin(),
],
};

View File

@ -0,0 +1,59 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const lessLoaderConfig = require('./lessLoaderConfig');
const { createMockMiddleware } = require('umi-mock-middleware');
module.exports = merge(baseWebpackConfig, {
mode: 'development',
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: '/',
filename: 'build.js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader'],
},
lessLoaderConfig('development'),
],
},
devServer: {
port: process.env.PORT || 3000,
host: '0.0.0.0',
historyApiFallback: {
rewrites: [{ from: /./, to: '/index.html' }],
},
disableHostCheck: true,
hot: true,
open: true,
headers: { 'Access-Control-Allow-Origin': '*' },
// 解析body对接真实服务端环境需要注释掉
before(app) {
// var bodyParser = require("body-parser");
// app.use(bodyParser.json());
if (process.env.MOCK !== 'none') {
app.use(createMockMiddleware());
}
},
proxy: {
'/api': {
target: 'http://localhost:3000',
},
},
},
performance: {
hints: false,
},
devtool: '#source-map',
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
filename: 'index.html',
inject: true,
}),
],
});

View File

@ -0,0 +1,64 @@
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
let lessLoaderConfig = require('./lessLoaderConfig')('production');
module.exports = merge(baseWebpackConfig, {
output: {
path: path.resolve(__dirname, '../_site'),
publicPath: '/',
filename: '[name].[contenthash:8].js',
chunkFilename: '[contenthash:8].async.js',
},
module: {
rules: [
lessLoaderConfig,
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
],
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial',
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true,
},
},
},
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"',
},
}),
new HtmlWebpackPlugin({
template: './public/index.html',
inject: true,
production: true,
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].css',
chunkFilename: '[id].[contenthash:8].css',
}),
],
});

View File

@ -1,6 +1,3 @@
<template>
<div id="carbon-ads" :class="isMobile ? 'carbon-mobile' : ''" />
</template>
<script>
const carbonUrls = {
'www.antdv.com': '//cdn.carbonads.com/carbon.js?serve=CK7DL2JW&placement=antdvcom',
@ -19,7 +16,7 @@ export default {
},
watch: {
$route(e, t) {
const adId = '#carbonads';
let adId = '#carbonads';
// if(isGitee) {
// adId = '#cf';
// }
@ -55,6 +52,9 @@ export default {
}
},
},
render() {
return <div id="carbon-ads" class={this.isMobile ? 'carbon-mobile' : ''} />;
},
};
</script>
<style lang="less">

View File

@ -0,0 +1,34 @@
<script>
export default {
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
render() {
return (
<div class="google-ads" id="API">
<ins
ref="ins"
class="adsbygoogle"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="7647023136"
style="display: inline-block; width: 728px; height: 90px"
></ins>
</div>
);
},
};
</script>

View File

@ -0,0 +1,35 @@
<script>
export default {
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
render() {
return (
<div class="google-ads" id="api">
<ins
ref="ins"
style="display:block"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="3952358732"
data-ad-format="auto"
data-full-width-responsive="true"
></ins>
</div>
);
},
};
</script>

View File

@ -0,0 +1,35 @@
<script>
export default {
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
render() {
return (
<div class="google-ads">
<ins
ref="ins"
style="display:block"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="9507921838"
data-ad-format="auto"
data-full-width-responsive="true"
></ins>
</div>
);
},
};
</script>

View File

@ -0,0 +1,34 @@
<script>
export default {
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
render() {
return (
<div style="width: 300px;float: right;margin-top: 75px;position: relative;right: 0;bottom: 0;padding: 0;z-index: 9;">
<ins
ref="ins"
class="adsbygoogle"
style="display:inline-block;width:300px;height:100px"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="2774992529"
></ins>
</div>
);
},
};
</script>

View File

@ -0,0 +1,34 @@
<script>
export default {
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
render() {
return (
<div class="google-ads">
<ins
ref="ins"
class="adsbygoogle"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="2425414214"
style="display: inline-block; width: 728px; height: 90px"
></ins>
</div>
);
},
};
</script>

View File

@ -1,14 +1,12 @@
<template>
<div id="rice">
<div class="wwads-cn wwads-horizontal" data-id="62" style="max-width: 350px"></div>
<div class="wwads-cn wwads-horizontal" data-id="62" style="max-width: 350px" />
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
export default {
// mounted() {
// // this.load();
// this.load();
// },
// methods: {
// load() {
@ -23,7 +21,7 @@ export default defineComponent({
// this.scriptDom = e;
// },
// },
});
};
</script>
<style scoped>
#rice {

View File

@ -0,0 +1,27 @@
<template>
<div class="markdown api-container">
<slot v-if="isZhCN" name="cn" />
<slot v-else />
</div>
</template>
<script>
import { isZhCN } from '../utils/util';
import GoogleAds from './GoogleAds';
const showAd = false; // location.host.indexOf('antdv.com') > -1;
export default {
name: 'Api',
components: {
GoogleAds,
},
inject: {
demoContext: { default: {} },
},
data() {
return {
showAd,
isZhCN: isZhCN(this.demoContext.name),
};
},
};
</script>

View File

@ -0,0 +1,230 @@
<template>
<section :id="id" :class="['code-box', codeExpand ? 'expand' : '']">
<section class="code-box-demo">
<template v-if="iframeDemo[iframeDemoKey]">
<div class="browser-mockup with-url">
<iframe :src="iframeDemo[iframeDemoKey]" height="360" />
</div>
</template>
<template v-else>
<slot name="component" />
</template>
</section>
<section class="code-box-meta markdown">
<slot v-if="isZhCN" name="description" />
<slot v-else name="us-description" />
<div class="code-box-actions">
<a-tooltip
:title="copied ? 'Copied!' : 'Copy code'"
:visible="copyTooltipVisible"
@visibleChange="onCopyTooltipVisibleChange"
>
<a-icon
v-clipboard:copy="sourceCode"
v-clipboard:success="handleCodeCopied"
:type="copied && copyTooltipVisible ? 'check' : 'copy'"
class="code-box-code-copy"
/>
</a-tooltip>
<a-tooltip :title="codeExpand ? 'Hide Code' : 'Show Code'">
<span class="code-expand-icon">
<img
width="16"
alt="expand code"
src="https://gw.alipayobjects.com/zos/rmsportal/wSAkBuJFbdxsosKKpqyq.svg"
:class="codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'"
@click="handleCodeExpand"
/>
<img
width="16"
alt="expand code"
src="https://gw.alipayobjects.com/zos/rmsportal/OpROPHYqWmrMDBFMZtKF.svg"
:class="codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'"
@click="handleCodeExpand"
/>
</span>
</a-tooltip>
</div>
</section>
<transition appear :css="false" @enter="enter" @leave="leave">
<section
v-show="codeExpand"
class="highlight-wrapper"
style="position: relative;"
v-html="getCode()"
/>
</transition>
</section>
</template>
<script>
import animate from 'ant-design-vue/es/_util/openAnimation';
import BaseMixin from 'ant-design-vue/es/_util/BaseMixin';
import { isZhCN } from '../utils/util';
import { dev } from '../build/config';
export default {
name: 'DemoBox',
mixins: [BaseMixin],
inject: {
iframeDemo: { default: {} },
demoContext: { default: {} },
},
props: {
jsfiddle: Object,
isIframe: Boolean,
},
data() {
window.test = this;
const { name = '' } = this.demoContext;
const { us, cn, sourceCode } = this.jsfiddle;
const usTitle = (us.split('#### ')[1] || '').split('\n')[0] || '';
const cnTitle = (cn.split('#### ')[1] || '').split('\n')[0] || '';
if (process.env.NODE_ENV !== 'production' && usTitle === '') {
throw new Error(`not have usTitle`);
}
const iframeDemoKey = usTitle
.split(' ')
.join('-')
.toLowerCase();
const id = [
'components',
name.replace(/-cn\/?$/, '') || dev.componentName,
'demo',
...usTitle.split(' '),
]
.join('-')
.toLowerCase();
if (this.demoContext.store) {
const { currentSubMenu } = this.demoContext.store.getState();
this.demoContext.store.setState({
currentSubMenu: [...currentSubMenu, { cnTitle, usTitle, id }],
});
}
return {
codeExpand: false,
isZhCN: isZhCN(name),
copied: false,
copyTooltipVisible: false,
sourceCode: decodeURIComponent(escape(window.atob(sourceCode))),
id,
iframeDemoKey,
isDemo: true,
};
},
methods: {
getCode() {
const { $slots } = this;
return decodeURIComponent(
escape(window.atob(($slots.code && $slots.code[0] && $slots.code[0].text) || '')),
);
},
handleCodeExpand() {
this.codeExpand = !this.codeExpand;
},
enter: animate.enter,
leave: animate.leave,
handleCodeCopied() {
this.setState({ copied: true });
},
onCopyTooltipVisibleChange(visible) {
if (visible) {
this.setState({
copyTooltipVisible: visible,
copied: false,
});
return;
}
this.setState({
copyTooltipVisible: visible,
});
},
},
};
</script>
<style scoped lang="less">
.box-demo {
padding: 0;
border: 1px solid #e9e9e9;
border-radius: 4px;
box-shadow: none;
margin-top: 20px;
margin-bottom: 20px;
}
.box-demo-show {
padding: 20px 25px 30px;
border-bottom: 1px solid #e9e9e9;
}
.box-demo-description {
position: relative;
padding: 17px 16px 15px 20px;
border-radius: 0 0 6px 6px;
-webkit-transition: background-color 0.4s ease;
transition: background-color 0.4s ease;
width: 100%;
font-size: 12px;
&.bordered {
border-bottom: 1px dashed #e9e9e9;
}
h3,
h4 {
position: absolute;
top: -14px;
padding: 1px 8px;
margin-left: -8px;
margin-top: 0;
margin-bottom: 0;
color: #777;
border-radius: 4px;
border-top-left-radius: 0;
background: #fff;
-webkit-transition: background-color 0.4s ease;
transition: background-color 0.4s ease;
.header-anchor {
display: none;
}
}
li {
line-height: 21px;
}
}
.box-demo-code {
-webkit-transition: height 0.2s ease-in-out;
transition: height 0.2s ease-in-out;
overflow: auto;
border-top: 1px dashed #e9e9e9;
pre {
margin: 0;
}
code {
margin: 0;
background: #f7f7f7;
padding: 0.2em 0.4em;
border-radius: 3px;
font-size: 0.9em;
border: 1px solid #eee;
}
}
.btn-toggle {
position: absolute;
right: 16px;
bottom: 17px;
cursor: pointer;
width: 18px;
height: 18px;
font-size: 18px;
line-height: 18px;
color: #999;
i {
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
&.open {
i {
-webkit-transform: rotate(-180deg);
-ms-transform: rotate(-180deg);
transform: rotate(-180deg);
}
}
}
</style>

View File

@ -1,16 +1,16 @@
<template>
<div>
<demo-box :jsfiddle="jsfiddle">
<template #component>
<template slot="component">
<slot />
</template>
<template #description>
<template slot="description">
<div class="demo-description" v-html="cnHtml" />
</template>
<template #us-description>
<template slot="us-description">
<div class="demo-description" v-html="usHtml" />
</template>
<template #code>
<template slot="code">
{{ codeStr }}
</template>
</demo-box>
@ -20,8 +20,8 @@
<script>
import marked from 'marked';
import Prism from 'prismjs';
// import 'prismjs/components/prism-jsx.min.js';
// import 'prismjs/components/prism-bash.min.js';
import 'prismjs/components/prism-jsx.min.js';
import 'prismjs/components/prism-bash.min.js';
const replaceDelimiters = function(str) {
return str.replace(/({{|}})/g, '<span>$1</span>');
};
@ -62,7 +62,10 @@ export default {
const us = this.code.match(usReg) || [];
const cnHtml = marked(cn[1].trim());
const usHtml = marked(us[1].trim());
const sourceCode = this.code.replace(cn[0], '').replace(us[0], '').trim();
const sourceCode = this.code
.replace(cn[0], '')
.replace(us[0], '')
.trim();
const codeHtml = marked('```html\n' + sourceCode + '```');
return {
codeStr: window.btoa(unescape(encodeURIComponent(codeHtml))),

View File

@ -0,0 +1,49 @@
import { Col, Row } from '../../components/grid';
import '../../components/grid/style';
function isEmptyElement(c) {
return !(c.tag || (c.text && c.text.trim() !== ''));
}
function filterEmpty(children = []) {
return children.filter(c => !isEmptyElement(c));
}
export default {
props: {
cols: {
type: [Number, String],
default: 2,
},
},
inject: {
demoContext: { default: {} },
},
render() {
const { cols, $slots } = this;
const isSingleCol = cols === 1;
const leftChildren = [];
const rightChildren = [];
const children = filterEmpty($slots.default);
children.forEach((demo, index) => {
if (index % 2 === 0 || isSingleCol) {
leftChildren.push(demo);
} else {
rightChildren.push(demo);
}
});
return (
<Row gutter={16}>
<Col
span={isSingleCol ? 24 : 12}
class={isSingleCol ? 'code-boxes-col-1-1' : 'code-boxes-col-2-1'}
>
{leftChildren}
</Col>
{isSingleCol ? null : (
<Col class="code-boxes-col-2-1" span={12}>
{rightChildren}
</Col>
)}
</Row>
);
},
};

View File

@ -0,0 +1,145 @@
<script>
import moment from 'moment';
export default {
props: {
isCN: Boolean,
},
render() {
const isCN = this.isCN;
const showJeecg = moment().isBefore(moment('2023-09-10'));
return (
<footer id="footer">
<div class="footer-wrap">
<a-row>
<a-col md={6} sm={24} xs={24}>
<div class="footer-center">
<h2>Ant Design</h2>
<div>
<a href="https://github.com/vueComponent/ant-design-vue" target="_blank ">
<span>GitHub</span>
</a>
<span></span>
<span>
<i class="anticon anticon-github"></i>
</span>
</div>
<div>
<a href="https://ant.design/docs/react/introduce-cn" target="_blank">
Ant Design
</a>
<span> - </span>
<span>React</span>
</div>
<div>
<a href="https://github.com/NG-ZORRO/ng-zorro-antd" target="_blank">
Ant Design
</a>
<span> - </span>
<span>Angular</span>
</div>
<div>
<a href="https://github.com/websemantics/awesome-ant-design" target="_blank ">
<span>Awesome Ant Design</span>
</a>
</div>
<div>
<a href="http://library.ant.design/" rel="noopener noreferrer" target="_blank">
AntD Library
</a>
</div>
</div>
</a-col>
<a-col md={6} sm={24} xs={24}>
<div class="footer-center">
<h2>{isCN ? '社区' : 'Community'}</h2>
{isCN ? (
<div>
<a href="https://zhuanlan.zhihu.com/ant-design-vue" target="_blank">
<span>知乎专栏</span>
</a>
</div>
) : (
''
)}
<div>
<a href="https://github.com/vueComponent/ant-design-vue/releases" target="_blank">
<span>{isCN ? '更新记录' : 'Change Log'}</span>
</a>
</div>
<div>
<a
rel="noopener noreferrer"
target="_blank"
href={`https://vuecomponent.github.io/issue-helper/${isCN ? '?lang=zh' : ''}`}
>
<span>{isCN ? '报告 Bug' : 'Bug Report'}</span>
</a>
</div>
</div>
</a-col>
<a-col md={6} sm={24} xs={24}>
<div class="footer-center">
<h2>{isCN ? '友情链接' : 'Links'}</h2>
{showJeecg && (
<div>
<a href="http://www.jeecg.com/" target="_blank">
Jeecg
</a>
</div>
)}
<div>
<a href="https://cn.vuejs.org/" target="_blank">
Vue
</a>
</div>
<div>
<a href="https://cli.vuejs.org/" target="_blank">
Vue CLI
</a>
</div>
<div>
<a href="https://antdv.formilyjs.org/" target="_blank">
@formily/antdv
</a>
</div>
</div>
</a-col>
<a-col md={6} sm={24} xs={24}>
<div class="footer-center">
<h2>
<img
alt=""
class="title-icon"
src="https://gw.alipayobjects.com/zos/rmsportal/nBVXkrFdWHxbZlmMbsaH.svg"
/>
<span>{isCN ? '更多产品' : 'More Products'}</span>
</h2>
<div>
<a href="https://antv.alipay.com/" rel="noopener noreferrer" target="_blank">
AntV
</a>
<span> - </span>
<span>{isCN ? '数据可视化' : 'Data Visualization'}</span>
</div>
<div>
<a href="https://eggjs.org/" rel="noopener noreferrer" target="_blank">
Egg
</a>
<span> - </span>
<span>{isCN ? '企业级 Node 开发框架' : 'Enterprise Node Framework'}</span>
</div>
</div>
</a-col>
</a-row>
</div>
<div style="padding: 10px 144px;">
备案号
<a href="http://beian.miit.gov.cn/" target="_blank">
浙ICP备19034671号
</a>
</div>
</footer>
);
},
};
</script>

View File

@ -0,0 +1,41 @@
<template>
<div v-show="visible" id="geektime">
<a
href="https://time.geekbang.org/course/intro/100024601?code=KHKYcoBU6vZa8nMglg7AWfDxxi3BWrz9INAzAY3umPk%3D"
target="_blank"
>
<img width="150" alt="Vue 实战教程" src="https://qn.antdv.com/geektime-vue.jpeg" />
</a>
<div class="close" @click="visible = false">
<a-icon type="close" />
</div>
</div>
</template>
<script>
export default {
props: ['isMobile'],
data() {
return {
visible: true,
};
},
};
</script>
<style lang="less" scoped>
#geektime {
position: fixed;
bottom: 10px;
right: 10px;
.close {
position: absolute;
text-align: center;
top: -8px;
right: -8px;
font-size: 16px;
padding: 15px;
color: #6e3041;
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<div
v-if="isEffective(effectiveTime)"
id="geektime-ads"
:class="isMobile ? 'geektime-ads-mobile' : ''"
>
<a
href="https://time.geekbang.org/column/intro/154?utm_term=zeusGZFFE&utm_source=app&utm_medium=tangjinzhou"
target="_blank"
>
<img height="100" alt="重学前端" src="https://qn.antdv.com/chongxueqianduan.jpg" />
</a>
</div>
</template>
<script>
import moment from 'moment';
export default {
props: ['isMobile'],
data() {
return {
visible: true,
effectiveTime: {
start: '2019-08-05 17:00:00',
end: '2019-09-05 17:00:00',
},
};
},
methods: {
isEffective({ start, end }) {
return moment().isBetween(start, end);
},
},
};
</script>
<style lang="less" scoped>
#geektime-ads {
width: 266px;
position: fixed;
left: 0;
bottom: 0px;
padding: 0;
overflow: hidden;
z-index: 9;
background-color: #fff;
border-radius: 3px;
font-size: 13px;
background: #f5f5f5;
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
}
#geektime-ads.geektime-ads-mobile {
width: 100%;
position: relative;
right: 0;
bottom: 0;
padding: 0;
margin-bottom: 15px;
}
</style>

View File

@ -0,0 +1,299 @@
<script>
import { isZhCN } from '../utils/util';
import docsearch from 'docsearch.js';
import packageInfo from '../../package.json';
import logo from '../public/logo.svg';
import antDesignVue from '../public/ant-design-vue.svg';
export default {
inject: {
demoContext: { default: {} },
},
props: {
name: String,
searchData: Array,
},
data() {
return {
visibleAdblockBanner: !!this.demoContext.blocked,
value: null,
showTopBanner: false,
};
},
watch: {
'demoContex.blocked': function blocked(val) {
this.visibleAdblockBanner = !!val;
},
},
mounted() {
this.initDocSearch(this.$i18n.locale);
},
methods: {
handleClose(key) {
localStorage.removeItem(`notification-key-${key}`);
localStorage.setItem(`notification-key-${key}`, true);
this.showTopBanner = false;
},
initDocSearch(locale) {
docsearch({
apiKey: '92003c1d1d07beef165b08446f4224a3',
indexName: 'antdv',
inputSelector: '#search-box input',
algoliaOptions: { facetFilters: [isZhCN(locale) ? 'cn' : 'en'] },
transformData(hits) {
hits.forEach(hit => {
hit.url = hit.url.replace('www.antdv.com', window.location.host);
hit.url = hit.url.replace('https:', window.location.protocol);
});
return hits;
},
debug: false, // Set debug to true if you want to inspect the dropdown
});
},
handleClick() {
const name = this.name;
const path = this.$route.path;
const newName = isZhCN(name) ? name.replace(/-cn\/?$/, '') : `${name}-cn`;
this.$router.push({
path: path.replace(name, newName),
});
this.$i18n.locale = isZhCN(name) ? 'en-US' : 'zh-CN';
},
onSelect(val) {
this.$router.push(val);
this.value = val;
},
closeTopBanner() {},
changeVersion(v) {
location.href = `https://${v}.antdv.com${this.$route.fullPath}`;
},
},
render() {
const name = this.name;
const visibleAdblockBanner = false; // this.visibleAdblockBanner;
const isCN = isZhCN(name);
const path = this.$route.path;
const selectedKeys = path === '/jobs/list-cn' ? ['jobs'] : ['components'];
return (
<header id="header">
{visibleAdblockBanner && (
<div class="adblock-banner">
{isZhCN
? '我们检测到你可能使用了 AdBlock 或 Adblock Plus它会影响到正常功能的使用如复制、展开代码等。'
: 'We have detected that you may use AdBlock or Adblock Plus, which will affect the use of normal functions (such as copying, expanding code, etc.)'}
<br />
{isZhCN
? '你可以将 Ant Design Vue 加入白名单,以便我们更好地提供服务。'
: 'You can add Ant Design Vue to the whitelist so that we can provide better services.'}
<CloseOutlined class="close-icon" onClick={() => (this.visibleAdblockBanner = false)} />
</div>
)}
{/* {!isCN && this.showTopBanner && (
<div class="global-notification">
<span>
v3 beta is out! Discover more about it on &nbsp;
<a href="https://next.antdv.com/" target="_blank">
next.antdv.com
</a>
&nbsp;
</span>
<a-icon
type="close"
style="position: absolute;top: 8px;right: 15px;"
onClick={() => this.handleClose('next')}
/>
</div>
)} */}
<a-row>
<a-col class="header-left" xxl={4} xl={5} lg={5} md={6} sm={24} xs={24}>
<router-link to={{ path: '/' }} id="logo">
<img alt="logo" height="32" src={logo} />
<img alt="logo" height="16" src={antDesignVue} />
</router-link>
<a-button
ghost
size="small"
onClick={this.handleClick}
class="header-lang-button"
key="lang-button"
>
{isCN ? 'English' : '中文'}
</a-button>
</a-col>
<a-col xxl={20} xl={19} lg={19} md={18} sm={0} xs={0}>
<div id="search-box">
<a-icon type="search" />
<a-input
placeholder={isCN ? '搜索组件...' : 'input search text'}
style="width: 200px"
/>
</div>
<span id="github-btn" class="github-btn">
<a class="gh-btn" href="//github.com/vueComponent/ant-design-vue/" target="_blank">
<span class="gh-ico" aria-hidden="true"></span>
<span class="gh-text">Star</span>
</a>
</span>
<a-button
ghost
size="small"
onClick={this.handleClick}
class="header-lang-button"
key="lang-button"
>
{isCN ? 'English' : '中文'}
</a-button>
<a-select size="small" defaultValue={packageInfo.version} class="version">
<a-select-option value={packageInfo.version}>{packageInfo.version}</a-select-option>
<a-select-option value="2.x" onClick={() => this.changeVersion('2x')}>
v2 LST
</a-select-option>
<a-select-option value="www" onClick={() => this.changeVersion('www')}>
v3 Current (Latest Features)
</a-select-option>
</a-select>
<a-menu selectedKeys={selectedKeys} mode="horizontal" class="menu-site" id="nav">
<a-menu-item key="components">
<router-link to="/docs/vue/introduce">{isCN ? '组件' : 'Components'}</router-link>
</a-menu-item>
<a-sub-menu
v-if="isZhCN"
key="advanced"
title={
<span style="position: relative">
高级组件
<a-badge color="red" style="position: absolute; top: -35px; right: -15px" />
</span>
}
>
<a-menu-item key="surely-table">
<a
href="https://www.surely.cool"
target="_blank"
rel="noopener noreferrer"
style="position: relative;"
>
Surely Table
</a>
</a-menu-item>
</a-sub-menu>
{isCN ? (
<a-menu-item key="store">
<a
href="https://store.antdv.com/pro/"
target="_blank"
style="position: relative;"
>
商店
</a>
</a-menu-item>
) : (
<a-menu-item key="store">
<a
href="https://store.antdv.com/pro/?lang=en"
target="_blank"
style="position: relative;"
>
Store{' '}
</a>
</a-menu-item>
)}
{isCN ? (
<a-menu-item key="geektime">
<a
href="https://time.geekbang.org/course/intro/100024601?code=KHKYcoBU6vZa8nMglg7AWfDxxi3BWrz9INAzAY3umPk%3D"
target="_blank"
style="position: relative;"
>
Vue 实战教程
</a>
</a-menu-item>
) : null}
<a-menu-item key="sponsor">
<router-link to={{ path: isCN ? '/docs/vue/sponsor-cn/' : '/docs/vue/sponsor/' }}>
{isCN ? '支持我们' : 'Support us'}
</router-link>
</a-menu-item>
<a-sub-menu key="Ecosystem" title={isCN ? '更多' : 'More'}>
<a-menu-item key="pro">
<a target="_blank" href="https://pro.antdv.com">
Pro (Admin)
</a>
</a-menu-item>
<a-menu-item key="vip">
<a target="_blank" href="https://store.antdv.com/pro/">
Pro For VIP
</a>
</a-menu-item>
<a-menu-item key="design">
<router-link
to={{ path: isCN ? '/docs/vue/download-cn/' : '/docs/vue/download/' }}
>
{isCN ? '设计资源' : 'Design Resources'}
</router-link>
</a-menu-item>
<a-menu-item key="vscode">
<a
target="_blank"
href="https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper"
>
VS Code Extension
</a>
</a-menu-item>
<a-menu-item key="awesome">
<a target="_blank" href="https://github.com/vueComponent/ant-design-vue-awesome">
Awesome
</a>
</a-menu-item>
<a-menu-item key="qq1">
<a>QQ 1(217490093) 已满</a>
</a-menu-item>
<a-menu-item key="qq2">
<a>QQ 2(809774695) 已满</a>
</a-menu-item>
<a-menu-item key="qq3">
<a>QQ 3(927828249)</a>
</a-menu-item>
</a-sub-menu>
</a-menu>
</a-col>
</a-row>
</header>
);
},
};
</script>
<style scope>
.adblock-banner {
position: relative;
z-index: 100;
min-width: 1000px;
padding: 16px;
line-height: 28px;
color: #8590a6;
text-align: center;
background-color: #ebebeb;
}
.close-icon {
position: absolute;
top: 15px;
right: 15px;
}
.global-notification {
text-align: center;
background: #001529;
padding: 20px 0;
font-size: 16px;
position: fixed;
bottom: 0;
width: 100%;
color: #fff;
z-index: 99;
}
.global-notification a {
color: #177ddc;
}
</style>

View File

@ -0,0 +1,30 @@
<script>
// import * as AllDemo from '../demo'
export default {
props: {
name: String,
hash: String,
},
provide() {
return {
demoContext: this,
};
},
render() {
// const name = this.name
// const titleMap = {}
// for (const [title] of Object.entries(AllDemo)) {
// const key = `${title.replace(/(\B[A-Z])/g, '-$1').toLowerCase()}`
// titleMap[key] = title
// }
// const Demo = AllDemo[titleMap[name.replace(/-cn\/?$/, '')]]
// const hash = this.$route.hash.replace('#', '')
return (
<div id="iframe-page">
<router-view></router-view>
</div>
);
},
};
</script>

View File

@ -0,0 +1,375 @@
<script>
import { enquireScreen } from 'enquire-js';
import AllDemo from '../site/demo';
import Header from './header';
import Footer from './footer';
// import Geektime from './geektime';
import GeektimeAds from './geektime_ads';
import RightBottomAd from './right_bottom_ad';
// import Sponsors from './sponsors';
import zhCN from 'ant-design-vue/es/locale-provider/zh_CN';
import enUS from 'ant-design-vue/es/locale-provider/default';
import sortBy from 'lodash/sortBy';
import { isZhCN } from '../utils/util';
import { Provider, create } from '../../components/_util/store';
import NProgress from 'nprogress';
import MobileMenu from '../../components/vc-drawer/src';
import WWAds from './WWAds.vue';
import GoogleAds from './GoogleAds';
import SurelyVue from './surelyVue';
const docsList = [
{ key: 'introduce', enTitle: 'Ant Design of Vue', title: 'Ant Design of Vue' },
{ key: 'getting-started', enTitle: 'Getting Started', title: '快速上手' },
{ key: 'use-with-vue-cli', enTitle: 'Use in vue-cli', title: '在 vue-cli 中使用' },
{ key: 'customize-theme', enTitle: 'Customize Theme', title: '定制主题' },
{ key: 'changelog', enTitle: 'Change Log', title: '更新日志' },
{ key: 'i18n', enTitle: 'Internationalization', title: '国际化' },
{ key: 'faq', enTitle: 'FAQ', title: '常见问题' },
{ key: 'sponsor', enTitle: 'Sponsor', title: '支持我们' },
{ key: 'download', enTitle: 'Download Design Resources', title: '下载设计资源' },
];
const isGitee = window.location.host.indexOf('gitee.io') > -1;
const showAd = false; // location.host.indexOf('antdv.com') > -1;
export default {
provide() {
return {
demoContext: this,
};
},
props: {
name: String,
showDemo: Boolean,
showApi: Boolean,
},
data() {
this.store = create({
currentSubMenu: [],
});
this.subscribe();
let blocked = false;
setTimeout(() => {
const div = document.createElement('div');
div.className = 'adsbox';
document.body.appendChild(div);
blocked = 'none' === getComputedStyle(div).display;
}, 300);
return {
showSideBars: true,
currentSubMenu: [],
sidebarHeight: document.documentElement.offsetHeight,
isMobile: false,
blocked,
};
},
watch: {
'$route.path'() {
this.store.setState({ currentSubMenu: [] });
this.addSubMenu();
},
},
beforeDestroy() {
if (this.unsubscribe) {
this.unsubscribe();
}
clearTimeout(this.timer);
if (this.resizeEvent) {
this.resizeEvent.remove();
}
if (this.debouncedResize && this.debouncedResize.cancel) {
this.debouncedResize.cancel();
}
},
mounted() {
if (isGitee) {
this.$info({
title: '提示',
content: '访问国内镜像站点的用户请访问 antdv.com 站点',
okText: '立即跳转',
onOk() {
location.href = 'https://www.antdv.com';
},
});
}
this.$nextTick(() => {
this.addSubMenu();
const nprogressHiddenStyle = document.getElementById('nprogress-style');
if (nprogressHiddenStyle) {
this.timer = setTimeout(() => {
nprogressHiddenStyle.parentNode.removeChild(nprogressHiddenStyle);
}, 0);
}
enquireScreen(b => {
this.isMobile = !!b;
});
});
},
methods: {
addSubMenu() {
if (this.$route.path.indexOf('/docs/vue/') !== -1) {
this.$nextTick(() => {
const menus = [];
const doms = [...this.$refs.doc.querySelectorAll(['h2', 'h3'])];
doms.forEach(dom => {
const id = dom.id;
if (id) {
const title = dom.textContent.split('#')[0].trim();
menus.push({ cnTitle: title, usTitle: title, id });
}
});
this.currentSubMenu = menus;
});
}
},
subscribe() {
const { store } = this;
this.unsubscribe = store.subscribe(() => {
this.currentSubMenu = this.store.getState().currentSubMenu;
});
},
getSubMenu(isCN) {
const currentSubMenu = this.currentSubMenu;
const lis = [];
currentSubMenu.forEach(({ cnTitle, usTitle, id }, index) => {
const title = isCN ? cnTitle : usTitle;
lis.push(<a-anchor-link key={id + index} href={`#${id}`} title={title} />);
});
const showApi = this.$route.path.indexOf('/components/') !== -1;
return (
<a-anchor offsetTop={100} class="demo-anchor">
{lis}
{showApi ? <a-anchor-link key="API" title="API" href="#API" /> : ''}
</a-anchor>
);
},
getDocsMenu(isCN, pagesKey) {
const docsMenu = [];
docsList.forEach(({ key, enTitle, title }) => {
const k = isCN ? `${key}-cn` : key;
pagesKey.push({ name: k, url: `/docs/vue/${k}/`, title: isCN ? title : enTitle });
docsMenu.push(
<a-menu-item key={k}>
<router-link to={`/docs/vue/${k}/`}>{isCN ? title : enTitle}</router-link>
</a-menu-item>,
);
});
return docsMenu;
},
resetDocumentTitle(component, name, isCN) {
let titleStr = 'Ant Design Vue';
if (component) {
const { subtitle, title } = component;
const componentName = isCN ? subtitle + ' ' + title : title;
titleStr = componentName + ' - ' + titleStr;
} else {
const currentKey = docsList.filter(item => {
return item.key === name;
});
if (currentKey.length) {
titleStr = (isCN ? currentKey[0]['title'] : currentKey[0]['enTitle']) + ' - ' + titleStr;
}
}
document.title = titleStr;
},
mountedCallback() {
NProgress.done();
document.documentElement.scrollTop = 0;
},
},
render() {
const name = this.name;
const isCN = isZhCN(name);
const titleMap = {};
const menuConfig = {
General: [],
Layout: [],
Navigation: [],
'Data Entry': [],
'Data Display': [],
Feedback: [],
Other: [],
};
const pagesKey = [];
let prevPage = null;
let nextPage = null;
const searchData = [];
for (const [title, d] of Object.entries(AllDemo)) {
const type = d.type || 'Other';
const key = `${title.replace(/(\B[A-Z])/g, '-$1').toLowerCase()}`;
titleMap[key] = title;
AllDemo[title].key = key;
menuConfig[type] = menuConfig[type] || [];
menuConfig[type].push(d);
}
const docsMenu = this.getDocsMenu(isCN, pagesKey);
const reName = name.replace(/-cn\/?$/, '');
const MenuGroup = [];
for (const [type, menus] of Object.entries(menuConfig)) {
const MenuItems = [];
sortBy(menus, ['title']).forEach(({ title, subtitle, key }) => {
const linkValue = isCN
? [<span>{title}</span>, <span class="chinese">{subtitle}</span>]
: [<span>{title}</span>];
if (isCN) {
key = `${key}-cn`;
}
pagesKey.push({
name: key,
url: `/components/${key}/`,
title: isCN ? `${title} ${subtitle}` : title,
});
searchData.push({
title,
subtitle,
url: `/components/${key}/`,
});
MenuItems.push(
<a-menu-item key={key}>
<router-link to={`/components/${key}/`}>{linkValue}</router-link>
</a-menu-item>,
);
});
MenuGroup.push(<a-menu-item-group title={type}>{MenuItems}</a-menu-item-group>);
}
pagesKey.forEach((item, index) => {
if (item.name === name) {
prevPage = pagesKey[index - 1];
nextPage = pagesKey[index + 1];
}
});
let locale = zhCN;
if (!isCN) {
locale = enUS;
}
const config = AllDemo[titleMap[reName]];
this.resetDocumentTitle(config, reName, isCN);
const { isMobile, $route } = this;
return (
<div class="page-wrapper">
<Header searchData={searchData} name={name} />
<a-config-provider locale={locale}>
<div class="main-wrapper">
<a-row>
{isMobile ? (
<MobileMenu ref="sidebar" wrapperClassName="drawer-wrapper">
<SurelyVue />
<a-menu
class="aside-container menu-site"
selectedKeys={[name]}
defaultOpenKeys={['Components']}
inlineIndent={40}
mode="inline"
>
{docsMenu}
<a-sub-menu title={`Components(${searchData.length})`} key="Components">
{MenuGroup}
</a-sub-menu>
</a-menu>
</MobileMenu>
) : (
<a-col
ref="sidebar"
class="site-sidebar main-menu"
xxl={4}
xl={5}
lg={5}
md={6}
sm={8}
xs={12}
>
<a-affix>
<section class="main-menu-inner">
<SurelyVue />
<a-menu
class="aside-container menu-site"
selectedKeys={[name]}
defaultOpenKeys={['Components']}
inlineIndent={40}
mode="inline"
>
{docsMenu}
<a-sub-menu title={`Components(${searchData.length})`} key="Components">
{MenuGroup}
</a-sub-menu>
</a-menu>
</section>
</a-affix>
</a-col>
)}
<a-col xxl={20} xl={19} lg={19} md={18} sm={24} xs={24}>
<section class="main-container main-container-component">
{showAd ? <GeektimeAds isMobile={isMobile} /> : null}
<WWAds />
{!isMobile ? (
<div class={['toc-affix', isCN ? 'toc-affix-cn' : '']} style="width: 150px;">
{this.getSubMenu(isCN)}
</div>
) : null}
{this.showDemo ? (
<Provider store={this.store} key={isCN ? 'cn' : 'en'}>
<router-view
class={`demo-cols-${config.cols || 2}`}
{...{
directives: [
{
name: 'mountedCallback',
value: this.mountedCallback,
},
],
}}
></router-view>
</Provider>
) : (
''
)}
{this.showApi ? (
<div class="markdown api-container" ref="doc">
<router-view
{...{
directives: [
{
name: 'mountedCallback',
value: this.mountedCallback,
},
],
}}
></router-view>
</div>
) : (
''
)}
</section>
<section class="prev-next-nav">
{prevPage ? (
<router-link class="prev-page" to={`${prevPage.url}`}>
<a-icon type="left" />
&nbsp;&nbsp;{prevPage.title}
</router-link>
) : (
''
)}
{nextPage ? (
<router-link class="next-page" to={`${nextPage.url}`}>
{nextPage.title}&nbsp;&nbsp;
<a-icon type="right" />
</router-link>
) : (
''
)}
</section>
<Footer ref="footer" isCN={isCN} />
</a-col>
</a-row>
</div>
</a-config-provider>
{name.indexOf('back-top') === -1 ? <a-back-top /> : null}
<RightBottomAd isCN={isCN} isMobile={isMobile} />
</div>
);
},
};
</script>

View File

@ -0,0 +1,51 @@
<template>
<div class="markdown" v-html="marked(text)" />
</template>
<script>
import marked from 'marked';
import { isZhCN } from '../utils/util';
const renderer = new marked.Renderer();
renderer.heading = function(text, level) {
return (
'<h' + level + ' id="' + text.replace(/[^\w]+/g, '-') + '">' + text + '</h' + level + '>\n'
);
};
marked.setOptions({
renderer,
gfm: true,
tables: true,
breaks: true,
pedantic: true,
sanitize: true,
smartLists: true,
smartypants: true,
});
export default {
name: 'Md',
props: {
cn: String,
us: String,
},
inject: {
demoContext: { default: {} },
},
data() {
let text = '';
const { cn, us } = this;
if (this.$slots.default && this.$slots.default[0] && this.$slots.default[0].text) {
text = this.$slots.default[0].text;
} else {
text = isZhCN(this.demoContext.name) ? cn : us;
}
text = text || '';
text = text
.split('\n')
.map(t => t.trim())
.join('\n');
return {
marked,
text,
};
},
};
</script>

View File

@ -0,0 +1,61 @@
<template>
<div v-if="isCN" id="right-bottom">
<img width="150" :src="`https://next.antdv.com/common_rice.png?v=${v}`" />
<div v-if="isMobile" class="close" @click="visible = false">
<a-icon type="close" />
</div>
<!-- <span v-if="isCN">广</span> -->
</div>
</template>
<script>
import moment from 'moment';
const isEffective = (start, end) => {
return moment().isBetween(start, end);
};
export default {
components: {},
props: ['isCN', 'isMobile'],
data() {
return {
isEffective,
visible: true,
v: moment().date(),
ads: [
{
alt: 'geektime',
img: 'https://qn.antdv.com/geektime-web-small.jpg',
href: 'http://gk.link/a/10l8O',
visible: isEffective('2020-09-03 10:00:00', '2020-10-04 10:00:00'),
},
{
alt: 'powerproject',
img: 'https://qn.antdv.com/powerproject.jpeg?v=20200327',
href: 'http://www.powerproject.com.cn',
visible: isEffective('2020-03-27 17:00:00', '2020-09-28 17:00:00'),
},
],
};
},
};
</script>
<style lang="less" scoped>
#right-bottom {
position: fixed;
bottom: 10px;
right: 10px;
width: 150px;
border-radius: 5px;
overflow: hidden;
.close {
position: absolute;
text-align: center;
top: -8px;
right: -8px;
font-size: 16px;
padding: 15px;
color: #6e3041;
}
}
</style>

View File

@ -0,0 +1,66 @@
<template>
<div class="snd-ad">
<div class="sponsorsWrap">
<span v-if="!isCN" class="sponsorsTitle">
{{ isCN ? '赞助商' : 'Sponsors' }}
</span>
<ul>
<!-- <li class="sponsorsItem">
<a href="https://tipe.io/?ref=ant-design-vue" target="_blank">
<img height="51" src="https://cdn.tipe.io/tipe/tipe-cat-no-text.svg" alt="tipe" />
</a>
</li> -->
<li v-if="isCN && isEffective(effectiveTime.kkb)" class="sponsorsItem">
<a href="https://datayi.cn/w/Y9J3M2vR" target="_blank">
<img height="66" src="https://qn.antdv.com/kaikeba_ssr.jpeg" alt="kaikeba">
</a>
<span style="position: absolute; top: 0px;right: 10px">广告</span>
</li>
<!-- <li class="sponsorsItem">
<a-button type="primary" ghost style="font-size: 12px" @click="handleClick">
{{ isCN ? '成为赞助商' : 'Become a Sponsor' }}
</a-button>
</li> -->
</ul>
</div>
<a-modal v-model="visible" title="成为赞助商" @ok="visible = false">
如果您有品牌推广活动推广招聘推广社区合作等需求欢迎联系我们成为赞助商<br>
您的广告将出现在 And Design Vue 文档所有子页面及 GitHub Readme 等页面<br>
咨询邮箱<a href="mailto:antdv@foxmail.com">antdv@foxmail.com</a><br>
</a-modal>
</div>
</template>
<script>
import moment from 'moment';
export default {
props: ['isCN'],
data() {
return {
top: 50,
effectiveTime: {
bmatch: {
start: '2019-03-11',
end: '2019-06-11',
},
kkb: {
start: '2020-11-16 22:00:00',
end: '2021-05-17 22:00:00',
},
},
visible: false,
};
},
methods: {
isEffective({ start, end }) {
return moment().isBetween(start, end);
},
handleClick() {
if (this.isCN) {
this.visible = true;
} else {
window.open('https://opencollective.com/ant-design-vue#sponsor');
}
},
},
};
</script>

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