Merge branch 'dev' into next

This commit is contained in:
chenjiahan 2022-01-17 19:48:33 +08:00
commit bcb7eabff3
377 changed files with 5335 additions and 2565 deletions

View File

@ -96,7 +96,7 @@ Vant 3 supports modern browsers and Chrome >= 51、iOS >= 10.0 (same as Vue 3).
| Project | Description | | Project | Description |
| --- | --- | | --- | --- |
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components based on Vant | | [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components based on Vant |
| [mxdi9i7/vant-react](https://github.com/mxdi9i7/vant-react) | Mobile UI Components built on React and TS, inspired by Vant | | [rc-ui-lib](https://github.com/rancui/rc-ui-lib) | React mobile UI Components based on Vant |
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI | | [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro | | [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Online theme preview built on Vant UI | | [vant-theme](https://github.com/Aisen60/vant-theme) | Online theme preview built on Vant UI |

View File

@ -25,7 +25,7 @@
### 介绍 ### 介绍
Vant 是**有赞前端团队**开源的移动端组件库,于 2017 年开源,已持续维护 4 年时间。Vant 对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一。 Vant 是**有赞前端团队**开源的移动端组件库,于 2017 年开源。Vant 对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一。
目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant)、[Vue 3 版本](https://vant-contrib.gitee.io/vant/v3)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/mxdi9i7/vant-react)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。 目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant)、[Vue 3 版本](https://vant-contrib.gitee.io/vant/v3)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/mxdi9i7/vant-react)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。
@ -104,7 +104,7 @@ Vant 3 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一致
| 项目 | 描述 | | 项目 | 描述 |
| --- | --- | | --- | --- |
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 框架移动端组件库 | | [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 框架移动端组件库 |
| [mxdi9i7/vant-react](https://github.com/mxdi9i7/vant-react) | 基于 React 和 TS 构建的移动端组件库 | | [rc-ui-lib](https://github.com/rancui/rc-ui-lib) | 参照 Vant 打造的 React 框架移动端组件库 |
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 | | [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 | | [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 | | [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 |

View File

@ -31,7 +31,6 @@
}, },
"devDependencies": { "devDependencies": {
"@vant/cli": "^3.9.0", "@vant/cli": "^3.9.0",
"@vue/compiler-sfc": "^3.0.0",
"vue": "^3.0.0" "vue": "^3.0.0"
}, },
"eslintConfig": { "eslintConfig": {

View File

@ -0,0 +1 @@
require('../vant-use/build');

View File

@ -1,12 +1,17 @@
{ {
"name": "@vant/area-data", "name": "@vant/area-data",
"version": "1.1.3", "version": "1.2.1",
"description": "Vant 省市区数据", "description": "Vant 省市区数据",
"main": "./lib/index.js", "main": "dist/index.cjs.js",
"typings": "./lib/index.d.ts", "module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"scripts": { "scripts": {
"build": "rimraf ./lib && tsc", "clean": "rimraf ./dist",
"release": "pnpm build && npm publish", "dev": "node ./build.js -w",
"build:types": "tsc -p ./tsconfig.json --emitDeclarationOnly",
"build:bundle": "node ./build.js",
"build": "pnpm clean && pnpm build:bundle && pnpm build:types",
"release": "pnpm build && release-it",
"prepare": "pnpm build" "prepare": "pnpm build"
}, },
"publishConfig": { "publishConfig": {
@ -20,5 +25,16 @@
}, },
"bugs": "https://github.com/youzan/vant/issues", "bugs": "https://github.com/youzan/vant/issues",
"author": "chenjiahan", "author": "chenjiahan",
"license": "MIT" "license": "MIT",
"devDependencies": {
"esbuild": "^0.13.15",
"release-it": "^14.2.2",
"typescript": "~4.5.2"
},
"release-it": {
"git": {
"tag": false,
"commitMessage": "release: @vant/area-data ${version}"
}
}
} }

View File

@ -390,7 +390,7 @@ export const areaList = {
711100: '新北市', 711100: '新北市',
711200: '宜兰县', 711200: '宜兰县',
711300: '新竹县', 711300: '新竹县',
711400: '桃园', 711400: '桃园',
711500: '苗栗县', 711500: '苗栗县',
711700: '彰化县', 711700: '彰化县',
711900: '嘉义县', 711900: '嘉义县',
@ -1290,8 +1290,8 @@ export const areaList = {
330110: '余杭区', 330110: '余杭区',
330111: '富阳区', 330111: '富阳区',
330112: '临安区', 330112: '临安区',
330113: '钱塘区', 330113: '临平区',
330114: '临平区', 330114: '钱塘区',
330122: '桐庐县', 330122: '桐庐县',
330127: '淳安县', 330127: '淳安县',
330182: '建德市', 330182: '建德市',

View File

@ -1,8 +1,7 @@
{ {
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"target": "ES2019", "outDir": "./dist",
"outDir": "./lib",
"declaration": true "declaration": true
}, },
"include": ["src/**/*"] "include": ["src/**/*"]

View File

@ -1,30 +0,0 @@
module.exports = function (api, options) {
if (api) {
api.cache.never();
}
const { BABEL_MODULE, NODE_ENV } = process.env;
const isTest = NODE_ENV === 'test';
const useESModules = BABEL_MODULE !== 'commonjs' && !isTest;
return {
presets: [
[
require.resolve('@babel/preset-env'),
{
modules: useESModules ? false : 'commonjs',
loose: options.loose,
},
],
require.resolve('@babel/preset-typescript'),
],
plugins: [
[
require.resolve('@vue/babel-plugin-jsx'),
{
enableObjectSlots: options.enableObjectSlots,
},
],
],
};
};

View File

@ -16,8 +16,7 @@ const DEFAULT_CONFIG = {
setupFilesAfterEnv: [JEST_SETUP_FILE], setupFilesAfterEnv: [JEST_SETUP_FILE],
moduleFileExtensions: ['js', 'jsx', 'vue', 'ts', 'tsx'], moduleFileExtensions: ['js', 'jsx', 'vue', 'ts', 'tsx'],
transform: { transform: {
'\\.(vue)$': 'vue3-jest', '\\.(js|jsx|ts|tsx|vue)$': '<rootDir>/node_modules/@vant/cli/cjs/jest.transformer.cjs',
'\\.(js|jsx|ts|tsx)$': 'babel-jest',
}, },
transformIgnorePatterns: ['/node_modules/(?!(@vant/cli))/'], transformIgnorePatterns: ['/node_modules/(?!(@vant/cli))/'],
snapshotSerializers: ['jest-serializer-html'], snapshotSerializers: ['jest-serializer-html'],

View File

@ -0,0 +1,92 @@
const sfc = require('vue/compiler-sfc');
const babel = require('@babel/core');
const esbuild = require('esbuild');
const nodePath = require('path');
const isJsxFile = (path) => /\.(j|t)sx$/.test(path);
const isTsxFile = (path) => /\.tsx$/.test(path);
const isVueFile = (path) => /\.vue$/.test(path);
const transformJsx = (code, path) => {
const babelResult = babel.transformSync(code, {
filename: path,
babelrc: false,
presets: isTsxFile(path) ? ['@babel/preset-typescript'] : [],
plugins: [['@vue/babel-plugin-jsx']],
});
return babelResult?.code || '';
};
const transformSFC = (code, path) => {
const parsedPath = nodePath.parse(path);
const { descriptor, errors } = sfc.parse(code, {
filename: parsedPath.base,
sourceRoot: parsedPath.dir,
});
if (errors.length) {
errors.forEach((error) => console.error(error));
return '';
}
const output = [];
let bindingMetadata = {};
if (descriptor.script) {
const content = descriptor.script.content.replace(
'export default',
'const script ='
);
output.push(content);
} else if (descriptor.scriptSetup) {
const result = sfc.compileScript(descriptor, {
id: 'mock',
});
const content = result.content.replace('export default', 'const script =');
output.push(content);
if (result.bindings) {
bindingMetadata = result.bindings;
}
} else {
output.push(`const script = {};`);
}
if (descriptor.template) {
const render = sfc.compileTemplate({
id: 'mock',
source: descriptor.template.content,
filename: path,
compilerOptions: {
bindingMetadata,
},
}).code;
output.push(render);
output.push('script.render = render;');
}
output.push('export default script;');
return output.join('\n');
};
const transformScript = (code) =>
esbuild.transformSync(code, {
target: 'es2016',
format: 'cjs',
loader: 'ts',
}).code;
module.exports = {
canInstrument: true,
process(code, path) {
if (isVueFile(path)) {
code = transformSFC(code, path);
}
if (isJsxFile(path)) {
code = transformJsx(code, path);
}
return transformScript(code);
},
};

View File

@ -21,8 +21,6 @@
- [site.simulator.url](#sitesimulatorurl) - [site.simulator.url](#sitesimulatorurl)
- [site.htmlMeta](#sitehtmlmeta) - [site.htmlMeta](#sitehtmlmeta)
- [site.enableVConsole](#siteenablevconsole) - [site.enableVConsole](#siteenablevconsole)
- [Babel](#babel)
- [默认配置](#----)
- [Postcss](#postcss) - [Postcss](#postcss)
- [默认配置](#-----1) - [默认配置](#-----1)
- [browserslist](#browserslist) - [browserslist](#browserslist)
@ -337,36 +335,13 @@ module.exports = {
是否在 dev 时开启 [vConsole](https://github.com/Tencent/vConsole) 调试,用于移动端 debug。 是否在 dev 时开启 [vConsole](https://github.com/Tencent/vConsole) 调试,用于移动端 debug。
## Babel
通过根目录下的`babel.config.js`文件可以对 Babel 进行配置。
### 默认配置
推荐使用`vant-cli`内置的 preset配置如下
```js
module.exports = {
presets: ['@vant/cli/preset'],
};
```
`@vant/cli/preset`中默认包含了以下插件:
- @babel/preset-env不含 core-js
- @babel/preset-typescript
- @babel/plugin-transform-object-assign
- @babel/plugin-proposal-optional-chaining
- @babel/plugin-proposal-nullish-coalescing-operator
- @vue/babel-preset-jsx
## Postcss ## Postcss
通过根目录下的`postcss.config.js`文件可以对 Postcss 进行配置。 通过根目录下的`postcss.config.js`文件可以对 Postcss 进行配置。
### 默认配置 ### 默认配置
`vant-cli`中默认的 Postcss 配置如下: `vant-cli` 中默认的 Postcss 配置如下:
```js ```js
module.exports = { module.exports = {
@ -378,7 +353,7 @@ module.exports = {
## browserslist ## browserslist
推荐在`package.json`文件里添加 browserslist 字段,这个值会被`@babel/preset-env``autoprefixer`用来确定目标浏览器的版本,保证编译后代码的兼容性。 推荐在 `package.json` 文件里添加 browserslist 字段,这个值会被 `autoprefixer` 用来确定目标浏览器的版本,保证编译后代码的兼容性。
在移动端浏览器中使用,可以添加如下配置: 在移动端浏览器中使用,可以添加如下配置:

View File

@ -14,7 +14,6 @@ project
│ ├─ home.md # 文档首页 │ ├─ home.md # 文档首页
│ └─ changelog.md # 更新日志 │ └─ changelog.md # 更新日志
├─ babel.config.js # Babel 配置文件
├─ vant.config.mjs # Vant Cli 配置文件 ├─ vant.config.mjs # Vant Cli 配置文件
├─ package.json ├─ package.json
└─ README.md └─ README.md

View File

@ -1,6 +1,6 @@
{ {
"name": "@vant/cli", "name": "@vant/cli",
"version": "4.0.0-rc.4", "version": "4.0.0-rc.5",
"type": "module", "type": "module",
"main": "lib/index.js", "main": "lib/index.js",
"typings": "lib/index.d.ts", "typings": "lib/index.d.ts",
@ -21,8 +21,7 @@
"cjs", "cjs",
"site", "site",
"template", "template",
"bin.js", "bin.js"
"preset.cjs"
], ],
"keywords": [ "keywords": [
"vant" "vant"
@ -42,32 +41,28 @@
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^9.0.13", "@types/fs-extra": "^9.0.13",
"@types/less": "^3.0.3", "@types/less": "^3.0.3",
"@types/lodash-es": "^4.17.5",
"@types/markdown-it": "^12.2.3", "@types/markdown-it": "^12.2.3",
"@vue/compiler-sfc": "^3.2.20", "vue": "^3.2.27"
"vue": "^3.2.20"
}, },
"dependencies": { "dependencies": {
"@types/jest": "^27.0.3",
"@babel/core": "^7.16.0", "@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@babel/preset-typescript": "^7.16.0", "@babel/preset-typescript": "^7.16.0",
"@docsearch/css": "3.0.0-alpha.41", "@docsearch/css": "3.0.0-alpha.41",
"@docsearch/js": "3.0.0-alpha.41", "@docsearch/js": "3.0.0-alpha.41",
"@types/jest": "^27.0.3",
"@vant/eslint-config": "^3.3.2", "@vant/eslint-config": "^3.3.2",
"@vant/markdown-vetur": "^2.2.0", "@vant/markdown-vetur": "^2.2.0",
"@vant/stylelint-config": "^1.4.2", "@vant/stylelint-config": "^1.4.2",
"@vant/touch-emulator": "^1.3.2", "@vant/touch-emulator": "^1.3.2",
"@vitejs/plugin-vue": "^1.9.4", "@vitejs/plugin-vue": "^2.0.0",
"@vitejs/plugin-vue-jsx": "^1.2.0", "@vitejs/plugin-vue-jsx": "^1.3.3",
"@vue/babel-plugin-jsx": "^1.1.1", "@vue/babel-plugin-jsx": "^1.1.1",
"autoprefixer": "^10.4.0", "autoprefixer": "^10.4.0",
"babel-jest": "^27.3.1",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"clean-css": "^5.2.2",
"commander": "^8.3.0", "commander": "^8.3.0",
"consola": "^2.15.3", "consola": "^2.15.3",
"conventional-changelog": "^3.1.24", "conventional-changelog": "^3.1.24",
"esbuild": "^0.14.2",
"eslint": "^8.1.0", "eslint": "^8.1.0",
"execa": "^5.1.1", "execa": "^5.1.1",
"fast-glob": "^3.2.7", "fast-glob": "^3.2.7",
@ -81,7 +76,6 @@
"jest-serializer-html": "^7.1.0", "jest-serializer-html": "^7.1.0",
"less": "^4.1.2", "less": "^4.1.2",
"lint-staged": "^12.1.2", "lint-staged": "^12.1.2",
"lodash-es": "^4.17.21",
"markdown-it": "^12.2.0", "markdown-it": "^12.2.0",
"markdown-it-anchor": "^8.4.1", "markdown-it-anchor": "^8.4.1",
"ora": "^6.0.1", "ora": "^6.0.1",
@ -91,13 +85,11 @@
"release-it": "^14.11.6", "release-it": "^14.11.6",
"stylelint": "^13.0.0", "stylelint": "^13.0.0",
"transliteration": "^2.2.0", "transliteration": "^2.2.0",
"ts-jest": "^27.0.7",
"typescript": "^4.5.2", "typescript": "^4.5.2",
"vite": "^2.6.13", "vite": "^2.7.10",
"vite-plugin-html": "^2.1.1", "vite-plugin-html": "^2.1.1",
"vite-plugin-md": "^0.11.4", "vite-plugin-md": "^0.11.4",
"vue-router": "^4.0.12", "vue-router": "^4.0.12"
"vue3-jest": "^27.0.0-alpha.2"
}, },
"release-it": { "release-it": {
"git": { "git": {

View File

@ -1,3 +0,0 @@
const babelConfig = require('./cjs/babel.config.cjs');
module.exports = (api, options) => babelConfig(api, options);

View File

@ -21,7 +21,7 @@ pre {
margin: 20px 0 0; margin: 20px 0 0;
+ p { + p {
margin-top: 20px; margin-top: 20px !important;
} }
} }

View File

@ -3,7 +3,9 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title><%= title %></title> <title><%= title %></title>
<% if (description) { %>
<meta name="description" content="<%= description %>" /> <meta name="description" content="<%= description %>" />
<% } %>
<link rel="icon" type="image/png" href="<%= logo %>" /> <link rel="icon" type="image/png" href="<%= logo %>" />
<meta <meta
name="viewport" name="viewport"

View File

@ -3,7 +3,9 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title><%- title %></title> <title><%- title %></title>
<% if (description) { %>
<meta name="description" content="<%- description %>" /> <meta name="description" content="<%- description %>" />
<% } %>
<link rel="icon" type="image/png" href="<%- logo %>" /> <link rel="icon" type="image/png" href="<%- logo %>" />
<meta <meta
name="viewport" name="viewport"

View File

@ -1,6 +1,6 @@
import fse from 'fs-extra';
import execa from 'execa'; import execa from 'execa';
import { join, relative } from 'path'; import { join, relative } from 'path';
import fse from 'fs-extra';
import { clean } from './clean.js'; import { clean } from './clean.js';
import { CSS_LANG } from '../common/css.js'; import { CSS_LANG } from '../common/css.js';
import { ora, consola } from '../common/logger.js'; import { ora, consola } from '../common/logger.js';
@ -27,12 +27,13 @@ import {
setModuleEnv, setModuleEnv,
setBuildTarget, setBuildTarget,
} from '../common/index.js'; } from '../common/index.js';
import type { Format } from 'esbuild';
const { remove, copy, readdir, existsSync } = fse; const { remove, copy, readdir, existsSync } = fse;
async function compileFile(filePath: string) { async function compileFile(filePath: string, format: Format) {
if (isScript(filePath)) { if (isScript(filePath)) {
return compileScript(filePath); return compileScript(filePath, format);
} }
if (isStyle(filePath)) { if (isStyle(filePath)) {
return compileStyle(filePath); return compileStyle(filePath);
@ -69,12 +70,14 @@ async function preCompileDir(dir: string) {
); );
} }
async function compileDir(dir: string) { async function compileDir(dir: string, format: Format) {
const files = await readdir(dir); const files = await readdir(dir);
await Promise.all( await Promise.all(
files.map((filename) => { files.map((filename) => {
const filePath = join(dir, filename); const filePath = join(dir, filename);
return isDir(filePath) ? compileDir(filePath) : compileFile(filePath); return isDir(filePath)
? compileDir(filePath, format)
: compileFile(filePath, format);
}) })
); );
} }
@ -86,13 +89,13 @@ async function copySourceCode() {
async function buildESMOutputs() { async function buildESMOutputs() {
setModuleEnv('esmodule'); setModuleEnv('esmodule');
setBuildTarget('package'); setBuildTarget('package');
await compileDir(ES_DIR); await compileDir(ES_DIR, 'esm');
} }
async function buildCJSOutputs() { async function buildCJSOutputs() {
setModuleEnv('commonjs'); setModuleEnv('commonjs');
setBuildTarget('package'); setBuildTarget('package');
await compileDir(LIB_DIR); await compileDir(LIB_DIR, 'cjs');
} }
async function buildTypeDeclarations() { async function buildTypeDeclarations() {

View File

@ -1,4 +1,3 @@
import { get } from 'lodash-es';
import { existsSync, readFileSync } from 'fs'; import { existsSync, readFileSync } from 'fs';
import { fileURLToPath, pathToFileURL } from 'url'; import { fileURLToPath, pathToFileURL } from 'url';
import { join, dirname, isAbsolute } from 'path'; import { join, dirname, isAbsolute } from 'path';
@ -74,7 +73,7 @@ export function getVantConfig() {
function getSrcDir() { function getSrcDir() {
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const srcDir = get(vantConfig, 'build.srcDir'); const srcDir = vantConfig.build?.srcDir;
if (srcDir) { if (srcDir) {
if (isAbsolute(srcDir)) { if (isAbsolute(srcDir)) {

View File

@ -1,4 +1,3 @@
import { get } from 'lodash-es';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { join, isAbsolute } from 'path'; import { join, isAbsolute } from 'path';
import { getVantConfig } from '../common/index.js'; import { getVantConfig } from '../common/index.js';
@ -8,7 +7,7 @@ type CSS_LANG = 'css' | 'less' | 'scss';
function getCssLang(): CSS_LANG { function getCssLang(): CSS_LANG {
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const preprocessor = get(vantConfig, 'build.css.preprocessor', 'less'); const preprocessor = vantConfig.build?.css?.preprocessor || 'less';
if (preprocessor === 'sass') { if (preprocessor === 'sass') {
return 'scss'; return 'scss';
@ -23,7 +22,7 @@ export function getCssBaseFile() {
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
let path = join(STYLE_DIR, `base.${CSS_LANG}`); let path = join(STYLE_DIR, `base.${CSS_LANG}`);
const baseFile = get(vantConfig, 'build.css.base', ''); const baseFile = vantConfig.build?.css?.base || '';
if (baseFile) { if (baseFile) {
path = isAbsolute(baseFile) ? baseFile : join(SRC_DIR, baseFile); path = isAbsolute(baseFile) ? baseFile : join(SRC_DIR, baseFile);
} }

View File

@ -1,5 +1,4 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import { get } from 'lodash-es';
import { sep, join } from 'path'; import { sep, join } from 'path';
import { SRC_DIR, getVantConfig } from './constant.js'; import { SRC_DIR, getVantConfig } from './constant.js';
import type { InlineConfig } from 'vite'; import type { InlineConfig } from 'vite';
@ -14,6 +13,7 @@ export const TEST_REGEXP = new RegExp('\\' + sep + 'test$');
export const ASSET_REGEXP = /\.(png|jpe?g|gif|webp|ico|jfif|svg|woff2?|ttf)$/i; export const ASSET_REGEXP = /\.(png|jpe?g|gif|webp|ico|jfif|svg|woff2?|ttf)$/i;
export const STYLE_REGEXP = /\.(css|less|scss)$/; export const STYLE_REGEXP = /\.(css|less|scss)$/;
export const SCRIPT_REGEXP = /\.(js|ts|jsx|tsx)$/; export const SCRIPT_REGEXP = /\.(js|ts|jsx|tsx)$/;
export const JSX_REGEXP = /\.(j|t)sx$/;
export const ENTRY_EXTS = ['js', 'ts', 'tsx', 'jsx', 'vue']; export const ENTRY_EXTS = ['js', 'ts', 'tsx', 'jsx', 'vue'];
export function removeExt(path: string) { export function removeExt(path: string) {
@ -46,33 +46,14 @@ export function getComponents() {
); );
} }
export function isDir(dir: string) { export const isDir = (dir: string) => lstatSync(dir).isDirectory();
return lstatSync(dir).isDirectory(); export const isDemoDir = (dir: string) => DEMO_REGEXP.test(dir);
} export const isTestDir = (dir: string) => TEST_REGEXP.test(dir);
export const isAsset = (path: string) => ASSET_REGEXP.test(path);
export function isDemoDir(dir: string) { export const isSfc = (path: string) => SFC_REGEXP.test(path);
return DEMO_REGEXP.test(dir); export const isStyle = (path: string) => STYLE_REGEXP.test(path);
} export const isScript = (path: string) => SCRIPT_REGEXP.test(path);
export const isJsx = (path: string) => JSX_REGEXP.test(path);
export function isTestDir(dir: string) {
return TEST_REGEXP.test(dir);
}
export function isAsset(path: string) {
return ASSET_REGEXP.test(path);
}
export function isSfc(path: string) {
return SFC_REGEXP.test(path);
}
export function isStyle(path: string) {
return STYLE_REGEXP.test(path);
}
export function isScript(path: string) {
return SCRIPT_REGEXP.test(path);
}
const camelizeRE = /-(\w)/g; const camelizeRE = /-(\w)/g;
const pascalizeRE = /(\w)(\w*)/g; const pascalizeRE = /(\w)(\w*)/g;
@ -135,7 +116,7 @@ export function smartOutputFile(filePath: string, content: string) {
export function mergeCustomViteConfig(config: InlineConfig) { export function mergeCustomViteConfig(config: InlineConfig) {
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const configureVite = get(vantConfig, 'build.configureVite'); const configureVite = vantConfig.build?.configureVite;
if (configureVite) { if (configureVite) {
return configureVite(config); return configureVite(config);

View File

@ -1,15 +1,17 @@
import postcss from 'postcss'; import postcss from 'postcss';
import postcssrc from 'postcss-load-config'; import postcssrc from 'postcss-load-config';
import CleanCss from 'clean-css'; import { transform } from 'esbuild';
import { POSTCSS_CONFIG_FILE } from '../common/constant.js'; import { POSTCSS_CONFIG_FILE } from '../common/constant.js';
const cleanCss = new CleanCss();
export async function compileCss(source: string | Buffer) { export async function compileCss(source: string | Buffer) {
const config = await postcssrc({}, POSTCSS_CONFIG_FILE); const config = await postcssrc({}, POSTCSS_CONFIG_FILE);
const { css } = await postcss(config.plugins as any).process(source, { const { css } = await postcss(config.plugins as any).process(source, {
from: undefined, from: undefined,
}); });
const result = await transform(css, {
return cleanCss.minify(css).styles; loader: 'css',
minify: true,
target: ['chrome53', 'safari10'],
});
return result.code;
} }

View File

@ -1,5 +1,7 @@
import { createRequire } from 'module'; import { createRequire } from 'module';
const require = createRequire(import.meta.url);
// allow to import from node_modules // allow to import from node_modules
// @import "~package-name/var.scss" // @import "~package-name/var.scss"
const tildeImporter = (url: string) => { const tildeImporter = (url: string) => {
@ -16,7 +18,6 @@ const tildeImporter = (url: string) => {
}; };
export async function compileSass(filePath: string) { export async function compileSass(filePath: string) {
const require = createRequire(import.meta.url);
const { renderSync } = require('sass'); const { renderSync } = require('sass');
const { css } = renderSync({ file: filePath, importer: tildeImporter }); const { css } = renderSync({ file: filePath, importer: tildeImporter });
return css; return css;

View File

@ -1,16 +1,18 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import babel from '@babel/core';
import esbuild, { type Format } from 'esbuild';
import { sep } from 'path'; import { sep } from 'path';
import { transformAsync } from '@babel/core'; import { isJsx, replaceExt } from '../common/index.js';
import { replaceExt } from '../common/index.js';
import { replaceCSSImportExt } from '../common/css.js'; import { replaceCSSImportExt } from '../common/css.js';
import { replaceScriptImportExt } from './get-deps.js'; import { replaceScriptImportExt } from './get-deps.js';
const { readFileSync, removeSync, outputFileSync } = fse; const { readFileSync, removeSync, outputFileSync } = fse;
export async function compileScript(filePath: string): Promise<void> { export async function compileScript(
return new Promise((resolve, reject) => { filePath: string,
format: Format
): Promise<void> {
if (filePath.includes('.d.ts')) { if (filePath.includes('.d.ts')) {
resolve();
return; return;
} }
@ -21,16 +23,34 @@ export async function compileScript(filePath: string): Promise<void> {
} }
code = replaceScriptImportExt(code, '.vue', ''); code = replaceScriptImportExt(code, '.vue', '');
transformAsync(code, { filename: filePath }) if (isJsx(filePath)) {
.then((result) => { const babelResult = await babel.transformAsync(code, {
if (result) { filename: filePath,
const jsFilePath = replaceExt(filePath, '.js'); babelrc: false,
presets: ['@babel/preset-typescript'],
removeSync(filePath); plugins: [
outputFileSync(jsFilePath, result.code); [
resolve(); '@vue/babel-plugin-jsx',
} {
}) enableObjectSlots: false,
.catch(reject); },
],
],
}); });
if (babelResult?.code) {
({ code } = babelResult);
}
}
const esbuildResult = await esbuild.transform(code, {
loader: 'ts',
target: 'es2016',
format,
});
({ code } = esbuildResult);
const jsFilePath = replaceExt(filePath, '.js');
removeSync(filePath);
outputFileSync(jsFilePath, code);
} }

View File

@ -1,7 +1,7 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import path from 'path'; import path from 'path';
import hash from 'hash-sum'; import hash from 'hash-sum';
import { parse, SFCBlock, compileTemplate } from '@vue/compiler-sfc'; import { parse, SFCBlock, compileTemplate } from 'vue/compiler-sfc';
import { replaceExt } from '../common/index.js'; import { replaceExt } from '../common/index.js';
const { remove, readFileSync, outputFile } = fse; const { remove, readFileSync, outputFile } = fse;

View File

@ -1,4 +1,3 @@
import { get } from 'lodash-es';
import { join } from 'path'; import { join } from 'path';
import { import {
pascalize, pascalize,
@ -72,8 +71,8 @@ export function genPackageEntry({
const names = getComponents(); const names = getComponents();
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const namedExport = get(vantConfig, 'build.namedExport', false); const namedExport = vantConfig.build?.namedExport || false;
const skipInstall = get(vantConfig, 'build.skipInstall', []).map(pascalize); const skipInstall = (vantConfig.build?.skipInstall || []).map(pascalize);
const version = process.env.PACKAGE_VERSION || getPackageJson().version; const version = process.env.PACKAGE_VERSION || getPackageJson().version;

View File

@ -1,5 +1,4 @@
import markdownVetur from '@vant/markdown-vetur'; import markdownVetur from '@vant/markdown-vetur';
import { get } from 'lodash-es';
import { import {
SRC_DIR, SRC_DIR,
VETUR_DIR, VETUR_DIR,
@ -11,13 +10,13 @@ import {
export function genVeturConfig() { export function genVeturConfig() {
const pkgJson = getPackageJson(); const pkgJson = getPackageJson();
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const options = get(vantConfig, 'build.vetur'); const options = vantConfig.build?.vetur;
if (options) { if (options) {
markdownVetur.parseAndWrite({ markdownVetur.parseAndWrite({
name: vantConfig.name, name: vantConfig.name,
path: SRC_DIR, path: SRC_DIR,
test: /zh-CN\.md/, test: /README\.md/,
version: pkgJson.version, version: pkgJson.version,
outputDir: VETUR_DIR, outputDir: VETUR_DIR,
...options, ...options,

View File

@ -1,5 +1,4 @@
import { join } from 'path'; import { join } from 'path';
import { get } from 'lodash-es';
import { createRequire } from 'module'; import { createRequire } from 'module';
import hljs from 'highlight.js'; import hljs from 'highlight.js';
import vitePluginMd from 'vite-plugin-md'; import vitePluginMd from 'vite-plugin-md';
@ -82,7 +81,7 @@ function getTitle(config: { title: string; description?: string }) {
} }
function getHTMLMeta(vantConfig: any) { function getHTMLMeta(vantConfig: any) {
const meta = get(vantConfig, 'site.htmlMeta'); const meta = vantConfig.site?.htmlMeta;
if (meta) { if (meta) {
return Object.keys(meta) return Object.keys(meta)
@ -99,8 +98,8 @@ export function getViteConfigForSiteDev(): InlineConfig {
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const siteConfig = getSiteConfig(vantConfig); const siteConfig = getSiteConfig(vantConfig);
const title = getTitle(siteConfig); const title = getTitle(siteConfig);
const baiduAnalytics = get(vantConfig, 'site.baiduAnalytics'); const baiduAnalytics = vantConfig.site?.baiduAnalytics;
const enableVConsole = isDev() && get(vantConfig, 'site.enableVConsole'); const enableVConsole = isDev() && vantConfig.site?.enableVConsole;
return { return {
root: SITE_SRC_DIR, root: SITE_SRC_DIR,
@ -136,6 +135,9 @@ export function getViteConfigForSiteDev(): InlineConfig {
data: { data: {
...siteConfig, ...siteConfig,
title, title,
// `description` is used by the HTML ejs template,
// so it needs to be written explicitly here to avoid error: description is not defined
description: siteConfig.description,
baiduAnalytics, baiduAnalytics,
enableVConsole, enableVConsole,
meta: getHTMLMeta(vantConfig), meta: getHTMLMeta(vantConfig),
@ -159,8 +161,8 @@ export function getViteConfigForSiteDev(): InlineConfig {
export function getViteConfigForSiteProd(): InlineConfig { export function getViteConfigForSiteProd(): InlineConfig {
const devConfig = getViteConfigForSiteDev(); const devConfig = getViteConfigForSiteDev();
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const outDir = get(vantConfig, 'build.site.outputDir', SITE_DIST_DIR); const outDir = vantConfig.build?.site?.outputDir || SITE_DIST_DIR;
const publicPath = get(vantConfig, 'build.site.publicPath', '/'); const publicPath = vantConfig.build?.site?.publicPath || '/';
return { return {
...devConfig, ...devConfig,

View File

@ -1,7 +1,6 @@
// some modules with missing type definitions // some modules with missing type definitions
declare module 'execa'; declare module 'execa';
declare module 'hash-sum'; declare module 'hash-sum';
declare module 'clean-css';
declare module 'release-it'; declare module 'release-it';
declare module 'conventional-changelog'; declare module 'conventional-changelog';
declare module '@vant/markdown-vetur'; declare module '@vant/markdown-vetur';

View File

@ -1,5 +1,13 @@
## Changelog ## Changelog
## 1.7.3
- complete https protocol
## 1.7.2
- add cash-o icon
## 1.7.1 ## 1.7.1
- add guide-o icon - add guide-o icon

View File

@ -17,16 +17,3 @@ pnpm add @vant/icons
- [Usage in Vue](https://youzan.github.io/vant/#/zh-CN/icon) - [Usage in Vue](https://youzan.github.io/vant/#/zh-CN/icon)
- [Usage in Weapp](https://youzan.github.io/vant-weapp/#/icon) - [Usage in Weapp](https://youzan.github.io/vant-weapp/#/icon)
## Contribution
### Update Icons
1. Update assets/icons.sketch
2. Make a Pull Request
### Add New Icon
1. Add new icon to assets/icons.sketch
2. Add icon name to src/config.js
3. Make a Pull Request

View File

@ -0,0 +1,47 @@
# 图标贡献指南
## 设计稿
Vant 图标库托管在 [iconfont.cn](https://iconfont.cn) 上,同时仓库中保留了一份完整的 Sketch 设计稿。
[在线预览链接](https://iconfont.cn/collections/detail?cid=31945)
## 更新流程
新增/更新图标的标准流程如下:
### 1. 绘制图标
在 Sketch 中绘制所需的图标,并更新到 `assets/icons.sketch` 文件中。
绘制图标前,请阅读:[iconfont - 图标绘制](https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.16&helptype=draw)。
### 2. 上传图标
从 Sketch 中导出图标对应的 SVG 文件,并上传到 [iconfont 项目](https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2553510)中。
<img src="https://img.yzcdn.cn/upload_files/2021/12/21/Fi0XXEorB1SVr_BT-Dz6txHOKNlB.png" style="width: 800px;">
> 此步骤需要图标库管理员权限,请联系 Vant 维护者进行添加。
### 3. 更新代码
在 iconfont 中将更新后的图标库下载到本地,并更新以下文件:
- `src/index.less`: 更新字体文件的 CDN 链接。
- `src/encode-woff2.less`: 更新字体文件的 base64 URL。
如果有新增图标,还需要更新以下文件:
- `src/config.js`: 增加新图标的英文名称。
- `src/common.less`: 增加新图标的样式类。
字体文件的 base64 URL 通过 [transfonter](https://transfonter.org/) 生成,步骤如下图所示:
<img src="https://img01.yzcdn.cn/upload_files/2021/12/21/FlMHanQNhDV1XWaw8spnAtHKumjW.png" style="width: 800px;">
### 4. 发布图标库
执行 `yarn release` 命令,发布 `@vant/icons` 到 npm。
发布完成后,在对应仓库中进行升级,即可使用新图标。

View File

@ -1,6 +1,6 @@
{ {
"name": "@vant/icons", "name": "@vant/icons",
"version": "1.7.1", "version": "1.7.3",
"description": "vant icons", "description": "vant icons",
"main": "./src/config.js", "main": "./src/config.js",
"types": "./src/config.d.ts", "types": "./src/config.d.ts",

View File

@ -973,3 +973,7 @@
.van-icon-guide-o:before { .van-icon-guide-o:before {
content: '\e74c'; content: '\e74c';
} }
.van-icon-cash-o:before {
content: '\e74d';
}

View File

@ -149,6 +149,7 @@ export default {
'shrink', 'shrink',
'shield-o', 'shield-o',
'guide-o', 'guide-o',
'cash-o',
], ],
filled: [ filled: [
// has corresponding outline icon // has corresponding outline icon

File diff suppressed because one or more lines are too long

View File

@ -5,10 +5,10 @@
font-style: normal; font-style: normal;
font-display: auto; font-display: auto;
font-family: 'vant-icon'; font-family: 'vant-icon';
src: url('//at.alicdn.com/t/font_2553510_61agzg96wm8.woff2?t=1631948257467') src: url('https://at.alicdn.com/t/font_2553510_5imfhdc20ag.woff2?t=1640074908811')
format('woff2'), format('woff2'),
url('//at.alicdn.com/t/font_2553510_61agzg96wm8.woff?t=1631948257467') url('https://at.alicdn.com/t/font_2553510_5imfhdc20ag.woff?t=1640074908811')
format('woff'), format('woff'),
url('//at.alicdn.com/t/font_2553510_61agzg96wm8.ttf?t=1631948257467') url('https://at.alicdn.com/t/font_2553510_5imfhdc20ag.ttf?t=1640074908811')
format('truetype'); format('truetype');
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
# vant-markdown-loader
Simple and fast vue markdown loader, transform markdown to vue component.
## Install
```shell
# with npm
npm i @vant/markdown-loader -D
# with yarn
yarn add @vant/markdown-loader -D
# with pnpm
pnpm add @vant/markdown-loader -D
```
## Options
- `enableMetaData`: Default `false`. Whether to use [front-matter](https://github.com/jxson/front-matter) to extract markdown meta data
- `linkOpen`: Default `true`. Whether to add target="\_blank" to all links
- `wrapper(html, fm)`: Format the returned content using a custom function
- `html`: The result of [markdown-it](https://github.com/markdown-it/markdown-it)'s render
- `fm`: See [fm(string)](https://github.com/jxson/front-matter#fmstring). If `enableMetaData` option is `false`, the value is `undefined`.
- `attributes`
- `body`
- `frontmatter`

View File

@ -1,26 +0,0 @@
{
"name": "@vant/markdown-loader",
"version": "4.1.1",
"description": "Simple and fast vue markdown loader",
"main": "src/index.js",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"repository": {
"type": "git",
"url": "https://github.com/youzan/vant.git",
"directory": "packages/vant-markdown-loader"
},
"bugs": "https://github.com/youzan/vant/issues",
"author": "chenjiahan",
"license": "MIT",
"dependencies": {
"front-matter": "^4.0.2",
"highlight.js": "^10.7.1",
"loader-utils": "^2.0.0",
"markdown-it": "^12.0.4",
"markdown-it-anchor": "^8.0.0",
"transliteration": "^2.2.0"
}
}

View File

@ -1,16 +0,0 @@
module.exports = function cardWrapper(html) {
const group = html
.replace(/<h3/g, ':::<h3')
.replace(/<h2/g, ':::<h2')
.split(':::');
return group
.map(fragment => {
if (fragment.indexOf('<h3') !== -1) {
return `<div class="card">${fragment}</div>`;
}
return fragment;
})
.join('');
};

View File

@ -1,42 +0,0 @@
const path = require('path');
const fs = require('fs');
const os = require('os');
const parser = require('./md-parser');
function hyphenate(str) {
return str.replace(/\B([A-Z])/g, '-$1').toLowerCase();
}
module.exports = function extraDemo(content) {
const isWin = /^win/.test(os.platform());
const markdownDir = path.dirname(this.resourcePath);
const demoLinks = [];
content = content.replace(
/<demo-code([\s\S]*?)>([\s\S]*?)<\/demo-code>/g,
function (_, attrs, link) {
link = link.trim(); // 去换行符
const tag = 'demo-code-' + hyphenate(path.basename(link, '.vue'));
let fullLink;
if (isWin) {
fullLink = path.posix.join(...markdownDir.split(path.sep), link);
} else {
fullLink = path.join(markdownDir, link);
}
demoLinks.indexOf(fullLink) === -1 && demoLinks.push(fullLink);
const demoContent = fs.readFileSync(fullLink, { encoding: 'utf8' });
const demoParseredContent = parser.render(
'```html\n' + demoContent + '\n```'
);
return `
<demo-playground${attrs}
origin-code="${escape(demoContent)}"
code-snippet="${escape(demoParseredContent)}">
<${tag} />
</demo-playground>
`;
}
);
return [content, demoLinks];
};

View File

@ -1,10 +0,0 @@
const hljs = require('highlight.js');
module.exports = function highlight(str, lang) {
if (lang && hljs.getLanguage(lang)) {
// https://github.com/highlightjs/highlight.js/issues/2277
return hljs.highlight(str, { language: lang, ignoreIllegals: true }).value;
}
return '';
};

View File

@ -1,117 +0,0 @@
const path = require('path');
const loaderUtils = require('loader-utils');
const frontMatter = require('front-matter');
const parser = require('./md-parser');
const linkOpen = require('./link-open');
const cardWrapper = require('./card-wrapper');
const extractDemo = require('./extract-demo');
const sideEffectTags = require('./side-effect-tags');
function camelize(str) {
return `-${str}`.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ''));
}
const sharedVueOptions = `mounted() {
const anchors = [].slice.call(this.$el.querySelectorAll('h2, h3, h4, h5'));
anchors.forEach(anchor => {
anchor.addEventListener('click', this.scrollToAnchor);
});
},
methods: {
scrollToAnchor(event) {
if (event.target.id) {
this.$router.push({
name: this.$route.name,
hash: '#' + event.target.id
})
}
}
},
`;
function wrapper(content) {
let demoLinks;
[content, demoLinks] = extractDemo.call(this, content);
content = cardWrapper(content);
// 不包含 demo-code 的 md 文件,直接使绑定 HTML
if (demoLinks.length === 0) {
content = escape(content);
return `
<script>
import { h } from 'vue';
const content = unescape(\`${content}\`);
export default {
${sharedVueOptions}
render() {
return h('section', { innerHTML: content });
}
};
</script>
`;
}
// 包含 demo-code 的 md 文件,需要走模版渲染
let styles;
[content, styles] = sideEffectTags(content);
return `
<template>
<section v-once>
${content}
</section>
</template>
<script>
${demoLinks
.map((link) => {
return `import DemoCode${camelize(
path.basename(link, '.vue')
)} from '${link}';`;
})
.join('\n')}
export default {
components: {
${demoLinks
.map((link) => `DemoCode${camelize(path.basename(link, '.vue'))}`)
.join(',')}
},
${sharedVueOptions}
};
</script>
${styles.join('\n')}
`;
}
module.exports = function (source) {
let options = loaderUtils.getOptions(this) || {};
this.cacheable && this.cacheable();
options = {
wrapper,
linkOpen: true,
...options,
};
let fm;
if (options.enableMetaData) {
fm = frontMatter(source);
source = fm.body;
}
if (options.linkOpen) {
linkOpen(parser);
}
return options.wrapper.call(this, parser.render(source), fm);
};

View File

@ -1,18 +0,0 @@
// add target="_blank" to all links
module.exports = function linkOpen(md) {
const defaultRender =
md.renderer.rules.link_open ||
function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
const aIndex = tokens[idx].attrIndex('target');
if (aIndex < 0) {
tokens[idx].attrPush(['target', '_blank']); // add new attribute
}
return defaultRender(tokens, idx, options, env, self);
};
};

View File

@ -1,14 +0,0 @@
const MarkdownIt = require('markdown-it');
const markdownItAnchor = require('markdown-it-anchor');
const highlight = require('./highlight');
const { slugify } = require('transliteration');
const parser = new MarkdownIt({
html: true,
highlight,
}).use(markdownItAnchor, {
level: 2,
slugify,
});
module.exports = parser;

View File

@ -1,14 +0,0 @@
module.exports = function sideEffectTags(content) {
const styles = [];
// 从模版中移除 script 标签
content = content.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/g, '');
// 从模版中移除 style 标签,并收集到 styles 数组中,以转移为 .vue 文件 的 style 标签
content = content.replace(/<style[\s\S]*?>([\s\S]*?)<\/style>/g, (_, css) => {
styles.push(`<style scoped>${css}</style>`);
return '';
});
return [content, styles];
};

View File

@ -3,9 +3,9 @@ import { VueTag, VeturTags, VeturAttributes, VeturAttribute } from './type';
export function genVeturTags(tags: VueTag[]) { export function genVeturTags(tags: VueTag[]) {
const veturTags: VeturTags = {}; const veturTags: VeturTags = {};
tags.forEach(tag => { tags.forEach((tag) => {
veturTags[tag.name] = { veturTags[tag.name] = {
attributes: tag.attributes ? tag.attributes.map(item => item.name) : [], attributes: tag.attributes ? tag.attributes.map((item) => item.name) : [],
}; };
}); });
@ -15,16 +15,16 @@ export function genVeturTags(tags: VueTag[]) {
export function genVeturAttributes(tags: VueTag[]) { export function genVeturAttributes(tags: VueTag[]) {
const veturAttributes: VeturAttributes = {}; const veturAttributes: VeturAttributes = {};
tags.forEach(tag => { tags.forEach((tag) => {
if (tag.attributes) { if (tag.attributes) {
tag.attributes.forEach(attr => { tag.attributes.forEach((attr) => {
let attribute: VeturAttribute = { const attribute: VeturAttribute = {
type: attr.value.type, type: attr.value.type,
description: `${attr.description}, 默认值: ${attr.default}` description: `${attr.description}, Default: ${attr.default}`,
} };
if (attr.options.length > 0) { if (attr.options.length > 0) {
attribute.options = attr.options attribute.options = attr.options;
} }
veturAttributes[`${tag.name}/${attr.name}`] = attribute; veturAttributes[`${tag.name}/${attr.name}`] = attribute;

View File

@ -11,6 +11,8 @@ function bundleBundle(format) {
bundle: true, bundle: true,
target: ['chrome53'], target: ['chrome53'],
outfile, outfile,
// preserve Chinese character
charset: 'utf8',
external: ['vue'], external: ['vue'],
entryPoints: ['./src/index.ts'], entryPoints: ['./src/index.ts'],
}).then(finish); }).then(finish);

View File

@ -34,7 +34,7 @@
"esbuild": "^0.13.15", "esbuild": "^0.13.15",
"release-it": "^14.0.2", "release-it": "^14.0.2",
"typescript": "~4.5.2", "typescript": "~4.5.2",
"vue": "^3.2.20" "vue": "^3.2.27"
}, },
"release-it": { "release-it": {
"git": { "git": {

View File

@ -1,11 +0,0 @@
module.exports = {
presets: [
[
'@vant/cli/preset.cjs',
{
loose: process.env.BUILD_TARGET === 'package',
enableObjectSlots: false,
},
],
],
};

View File

@ -16,6 +16,94 @@ Vant follows [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/).
## Details ## Details
### [v3.4.2](https://github.com/compare/v3.4.1...v3.4.2)
`2022-01-17`
**Feature**
- Cascader: add show-header prop [#10202](https://github.com/youzan/vant/issues/10202)
- Image: add position prop [#10142](https://github.com/youzan/vant/issues/10142)
- ImagePreview: improve zoom fluency [#10187](https://github.com/youzan/vant/issues/10187)
- Overlay: add lazy-render prop [#10180](https://github.com/youzan/vant/issues/10180)
- provide english version of web-types [#10207](https://github.com/youzan/vant/issues/10207)
**Bug Fixes**
- Calendar: incorrectly selected when a date is disabled [#10196](https://github.com/youzan/vant/issues/10196)
- Image: failed to hide loading when using lazy-load [#10193](https://github.com/youzan/vant/issues/10193)
- ImagePreview: incorrectly closed after zooming [#10188](https://github.com/youzan/vant/issues/10188)
- Skeleton: row prop can't be string type [#10172](https://github.com/youzan/vant/issues/10172)
- useHeight may get the wrong height [#10195](https://github.com/youzan/vant/issues/10195)
### [v3.4.1](https://github.com/compare/v3.4.0...v3.4.1)
`2022-01-10`
**Bug Fixes**
- Area: missing picker mask [#10164](https://github.com/youzan/vant/issues/10164)
- DatetimePicker: error in some edge cases [#10140](https://github.com/youzan/vant/issues/10140)
- Popover: fix gap under the triangle [#10148](https://github.com/youzan/vant/issues/10148)
### [v3.4.0](https://github.com/compare/v3.3.7...v3.4.0)
`2022-01-01`
**Bug Fixes**
- Icons: complete https protocol [#10079](https://github.com/youzan/vant/issues/10079)
- Picker: should not render mask and frame when options is empty [#10135](https://github.com/youzan/vant/issues/10135)
- Popup: close event emitted twice [#10132](https://github.com/youzan/vant/issues/10132)
- PullRefresh: may trigger browser bounce in some cases [#10080](https://github.com/youzan/vant/issues/10080)
- Step: fix inactive title style [#10049](https://github.com/youzan/vant/issues/10049)
- SwipeCell: should not trigger open event when opened [#10059](https://github.com/youzan/vant/issues/10059)
- swipe: delay load cause swipe error [#10052](https://github.com/youzan/vant/issues/10052) [#10069](https://github.com/youzan/vant/issues/10069)
- Tabs: should not render line when have no tab [#10063](https://github.com/youzan/vant/issues/10063)
**Feature**
- ActionBarIcon: add badge-props prop [#10096](https://github.com/youzan/vant/issues/10096)
- ActionSheet: add option slot [#10065](https://github.com/youzan/vant/issues/10065)
- Badge: add badge-props prop [#10095](https://github.com/youzan/vant/issues/10095)
- GridItem: add badge-props prop [#10097](https://github.com/youzan/vant/issues/10097)
- Icons: add cash-o icon [#10076](https://github.com/youzan/vant/issues/10076)
- ImagePreview: add overlayClass option [#10044](https://github.com/youzan/vant/issues/10044)
- Notify: add position prop [#10056](https://github.com/youzan/vant/issues/10056)
- Popover: add action slot [#10091](https://github.com/youzan/vant/issues/10091)
- Search: add click-left-icon、click-right-icon event [#10139](https://github.com/youzan/vant/issues/10139)
- SidebarItem: add badge-props prop [#10106](https://github.com/youzan/vant/issues/10106)
- Swipe: indicator slot add total param [#10060](https://github.com/youzan/vant/issues/10060)
- TabbarItem: add badge-props prop [#10092](https://github.com/youzan/vant/issues/10092)
- Tabs: add shrink prop [#10125](https://github.com/youzan/vant/issues/10125)
**style**
- PullRefresh: remove user-select: none [#10078](https://github.com/youzan/vant/issues/10078)
- TreeSelect: allow select text in content slot [#10081](https://github.com/youzan/vant/issues/10081)
**Types**
- define global components for volar [#10136](https://github.com/youzan/vant/issues/10136)
- Field: type prop allow all native types [#10042](https://github.com/youzan/vant/issues/10042)
- Popup: add PopupInstance type [#10062](https://github.com/youzan/vant/issues/10062)
- Search: fix missing event typing [#10134](https://github.com/youzan/vant/issues/10134)
### [v3.3.7](https://github.com/compare/v3.3.6...v3.3.7)
`2021-12-12`
**Feature**
- Badge: add position prop [#10024](https://github.com/youzan/vant/issues/10024)
**Bug Fixes**
- DatetimePicker: should update value after calling picker methods [#10029](https://github.com/youzan/vant/issues/10029)
- Field: fix the length of emoji [#10033](https://github.com/youzan/vant/issues/10033)
- Pagination: change event not work [#10018](https://github.com/youzan/vant/issues/10018)
- fix tree shaking is broken [#10034](https://github.com/youzan/vant/issues/10034)
### [v3.3.6](https://github.com/compare/v3.3.5...v3.3.6) ### [v3.3.6](https://github.com/compare/v3.3.5...v3.3.6)
`2021-12-05` `2021-12-05`

View File

@ -16,6 +16,95 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
## 更新内容 ## 更新内容
### [v3.4.2](https://github.com/compare/v3.4.1...v3.4.2)
`2022-01-17`
**Feature**
- Cascader: 新增 show-header 属性 [#10202](https://github.com/youzan/vant/issues/10202)
- Image: 新增 position 属性 [#10142](https://github.com/youzan/vant/issues/10142)
- ImagePreview: 优化缩放手势的流畅度 [#10187](https://github.com/youzan/vant/issues/10187)
- Overlay: 新增 lazy-render 属性 [#10180](https://github.com/youzan/vant/issues/10180)
- web-types.json 现在默认使用英文描述 [#10207](https://github.com/youzan/vant/issues/10207)
**Bug Fixes**
- Calendar: 修复范围选择包括被禁用的日期时可能选择错误的问题 [#10196](https://github.com/youzan/vant/issues/10196)
- Image: 修复使用 lazy-load 时可能无法正常加载的问题 [#10193](https://github.com/youzan/vant/issues/10193)
- ImagePreview: 修复快速缩放手势导致预览关闭的问题 [#10188](https://github.com/youzan/vant/issues/10188)
- Skeleton: 修复 row 属性为字符串类型时不生效的问题 [#10172](https://github.com/youzan/vant/issues/10172)
- NavBar: 修复在 safari 上占位元素高度错误的问题 [#10195](https://github.com/youzan/vant/issues/10195)
- Tabbar: 修复在 safari 上占位元素高度错误的问题 [#10195](https://github.com/youzan/vant/issues/10195)
### [v3.4.1](https://github.com/compare/v3.4.0...v3.4.1)
`2022-01-10`
**Bug Fixes**
- Area: 修复缺少遮罩层的问题 [#10164](https://github.com/youzan/vant/issues/10164)
- DatetimePicker: 修复边界场景下出现报错的问题 [#10140](https://github.com/youzan/vant/issues/10140)
- Popover: 修复箭头和弹出框之间存在缝隙的问题 [#10148](https://github.com/youzan/vant/issues/10148)
### [v3.4.0](https://github.com/compare/v3.3.7...v3.4.0)
`2022-01-01`
**Bug Fixes**
- Icons: 修复 URL 缺少协议导致个别浏览器出现异常的问题 [#10079](https://github.com/youzan/vant/issues/10079)
- Picker: 修复选项为空时也会渲染选择框的问题 [#10135](https://github.com/youzan/vant/issues/10135)
- Popup: 修复 close 事件触发两次的问题 [#10132](https://github.com/youzan/vant/issues/10132)
- PullRefresh: 修复在个别浏览器上会触发原生回弹效果的问题 [#10080](https://github.com/youzan/vant/issues/10080)
- Step: 修复 inactive-color 属性未正确生效的问题 [#10049](https://github.com/youzan/vant/issues/10049)
- SwipeCell: 修复打开状态下也会触发 open 事件的问题 [#10059](https://github.com/youzan/vant/issues/10059)
- swipe: 修复个别情况下无法正确滚动的问题 [#10052](https://github.com/youzan/vant/issues/10052) [#10069](https://github.com/youzan/vant/issues/10069)
- Tabs: 修复标签页为空时会渲染一个错误的底部条的问题 [#10063](https://github.com/youzan/vant/issues/10063)
**Feature**
- ActionBarIcon: 新增 badge-props 属性 [#10096](https://github.com/youzan/vant/issues/10096)
- ActionSheet: 新增 option 插槽 [#10065](https://github.com/youzan/vant/issues/10065)
- Badge: 新增 badge-props 属性 [#10095](https://github.com/youzan/vant/issues/10095)
- GridItem: 新增 badge-props 属性 [#10097](https://github.com/youzan/vant/issues/10097)
- Icons: 新增 cash-o 图标 [#10076](https://github.com/youzan/vant/issues/10076)
- ImagePreview: 新增 overlayClass 选项 [#10044](https://github.com/youzan/vant/issues/10044)
- Notify: 新增 position 属性 [#10056](https://github.com/youzan/vant/issues/10056)
- Popover: 新增 action 插槽 [#10091](https://github.com/youzan/vant/issues/10091)
- Search: 新增 click-left-icon、click-right-icon 事件 [#10139](https://github.com/youzan/vant/issues/10139)
- SidebarItem: 新增 badge-props 属性 [#10106](https://github.com/youzan/vant/issues/10106)
- Swipe: indicator 插槽新增 total 参数 [#10060](https://github.com/youzan/vant/issues/10060)
- TabbarItem: 新增 badge-props 属性 [#10092](https://github.com/youzan/vant/issues/10092)
- Tabs: 新增 shrink 属性 [#10125](https://github.com/youzan/vant/issues/10125)
**style**
- PullRefresh: 移除 `user-select: none` 样式 [#10078](https://github.com/youzan/vant/issues/10078)
- TreeSelect: 允许选中 content 插槽中的文字 [#10081](https://github.com/youzan/vant/issues/10081)
**Types**
- 增加所有组件的全局类型,在 volar 中提供默认提示 [#10136](https://github.com/youzan/vant/issues/10136)
- Field: 修复 type 属性定义不全的问题 [#10042](https://github.com/youzan/vant/issues/10042)
- Popup: 导出 PopupInstance 类型 [#10062](https://github.com/youzan/vant/issues/10062)
- Search: 修复事件类型定义不全的问题 [#10134](https://github.com/youzan/vant/issues/10134)
### [v3.3.7](https://github.com/compare/v3.3.6...v3.3.7)
`2021-12-12`
**Feature**
- Badge: 新增 position 属性 [#10024](https://github.com/youzan/vant/issues/10024)
**Bug Fixes**
- DatetimePicker: 修复调用 Picker 实例方法后日期未正确更新的问题 [#10029](https://github.com/youzan/vant/issues/10029)
- Field: 修复输入内容包含 emoji 时,长度计算错误的问题 [#10033](https://github.com/youzan/vant/issues/10033)
- Pagination: 修复 change 事件不触发的问题 [#10018](https://github.com/youzan/vant/issues/10018)
- 修复 tree shaking 不生效的问题 [#10034](https://github.com/youzan/vant/issues/10034)
### [v3.3.6](https://github.com/compare/v3.3.5...v3.3.6) ### [v3.3.6](https://github.com/compare/v3.3.5...v3.3.6)
`2021-12-05` `2021-12-05`
@ -59,15 +148,15 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
**Feature** **Feature**
- 新增 `package.json` 中的 `exports` 字段 [#9952](https://github.com/issues/9952) - 新增 `package.json` 中的 `exports` 字段 [#9952](https://github.com/youzan/vant/issues/9952)
- Tabbar: 支持在 route 模式下匹配子路由 [#9926](https://github.com/issues/9926) - Tabbar: 支持在 route 模式下匹配子路由 [#9926](https://github.com/youzan/vant/issues/9926)
- Tabs: 将 `van-tab__pane-wrapper` 类重命名为 `van-tab__panel-wrapper` [#9951](https://github.com/issues/9951) - Tabs: 将 `van-tab__pane-wrapper` 类重命名为 `van-tab__panel-wrapper` [#9951](https://github.com/youzan/vant/issues/9951)
**Bug Fixes** **Bug Fixes**
- Calendar: 修复 show-confirm 为 false 时不会限制最大日期范围的问题 [#9948](https://github.com/issues/9948) - Calendar: 修复 show-confirm 为 false 时不会限制最大日期范围的问题 [#9948](https://github.com/youzan/vant/issues/9948)
- Calendar: 修复 `scrollToDate` 方法无法精确滚动到对应日期的问题 [#9949](https://github.com/issues/9949) - Calendar: 修复 `scrollToDate` 方法无法精确滚动到对应日期的问题 [#9949](https://github.com/youzan/vant/issues/9949)
- Swipe: 修复开始滑动时未阻止 touchmove 事件行为的问题 [#9920](https://github.com/issues/9920) - Swipe: 修复开始滑动时未阻止 touchmove 事件行为的问题 [#9920](https://github.com/youzan/vant/issues/9920)
### [v3.3.1](https://github.com/compare/v3.3.0...v3.3.1) ### [v3.3.1](https://github.com/compare/v3.3.0...v3.3.1)
@ -75,7 +164,7 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
**Bug Fixes** **Bug Fixes**
- AddressEdit: 修复表单校验不通过时也会触发 save 事件的问题 [#9917](https://github.com/issues/9917) - AddressEdit: 修复表单校验不通过时也会触发 save 事件的问题 [#9917](https://github.com/youzan/vant/issues/9917)
### [v3.3.0](https://github.com/compare/v3.2.8...v3.3.0) ### [v3.3.0](https://github.com/compare/v3.2.8...v3.3.0)

View File

@ -8,8 +8,8 @@
### Issue 规范 ### Issue 规范
- 遇到问题时,请先确认这个问题是否已经在 issue 中有记录或者已被修复 - 遇到问题时,请先确认这个问题是否已经在 issue 中有记录或者已被修复
- 提 issue 时,请用简短的语言描述遇到的问题,并添加出现问题时的环境和复现步骤 - 提 issue 时,请用简短的语言描述遇到的问题,并添加出现问题时的环境和复现步骤
## 参与开发 ## 参与开发
@ -71,28 +71,38 @@ src
└─ README.zh-CN.md # 中文文档 └─ README.zh-CN.md # 中文文档
``` ```
### 代码规范
在编写代码时,请注意:
- 确保代码可以通过仓库的 ESLint 和 Stylelint 校验。
- 确保代码格式是规范的,使用 prettier 进行代码格式化。
- 确保没有使用超出兼容性范围的 API比如 `async/await`
## 提交 PR ## 提交 PR
### Pull Request 规范 ### 参考指南
如果你是第一次在 GitHub 上提 Pull Request ,可以阅读下面这两篇文章来学习: 如果你是第一次在 GitHub 上提 Pull Request ,可以阅读下面这两篇文章来学习:
- [如何优雅地在 GitHub 上贡献代码](https://segmentfault.com/a/1190000000736629) - [如何优雅地在 GitHub 上贡献代码](https://segmentfault.com/a/1190000000736629)
- [第一次参与开源](https://github.com/firstcontributions/first-contributions/blob/master/translations/README.chs.md) - [第一次参与开源](https://github.com/firstcontributions/first-contributions/blob/master/translations/README.chs.md)
#### 规范 ### Pull Request 规范
- 如果遇到问题,建议保持你的 PR 足够小。保证一个 PR 只解决一个问题或只添加一个功能 在提交 Pull Request 时,请注意:
- 当新增组件或者修改原有组件时,记得增加或者修改测试代码,保证代码的稳定
- 在 PR 中请添加合适的描述,并关联相关的 Issue - 如果遇到问题,建议保持你的 PR 足够小。保证一个 PR 只解决单个问题、添加单个功能。
- 当新增组件或者修改原有组件时,记得增加或者修改对应的单元测试,保证代码的稳定。
- 在 PR 中请添加合适的描述,并关联相关的 Issue。
### Pull Request 流程 ### Pull Request 流程
1. fork 主仓库,如果已经 fork 过,请同步主仓库的最新代码 1. fork 主仓库,如果已经 fork 过,请同步主仓库的最新代码
2. 基于 fork 后仓库的 dev 分支新建一个分支,比如 `feature/button_color` 2. 基于 fork 后仓库的 dev 分支新建一个分支,比如 `feature/button_color`
3. 在新分支上进行开发,开发完成后,提 Pull Request 到主仓库的 dev 分支 3. 在新分支上进行开发,开发完成后,提 Pull Request 到主仓库的 dev 分支
4. Pull Request 会在 Review 通过后被合并到主仓库 4. Pull Request 会在 Review 通过后被合并到主仓库
5. 等待 Vant 发布版本,一般是每周一次 5. 等待 Vant 发布版本,一般是每周一次
### 同步最新代码 ### 同步最新代码

View File

@ -48,7 +48,7 @@ Vant 3 supports modern browsers and Chrome >= 51、iOS >= 10.0 (same as Vue 3).
| Project | Description | | Project | Description |
| --- | --- | | --- | --- |
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components based on Vant | | [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components based on Vant |
| [mxdi9i7/vant-react](https://github.com/mxdi9i7/vant-react) | Mobile UI Components built on React and TS, inspired by Vant | | [rc-ui-lib](https://github.com/rancui/rc-ui-lib) | React Mobile UI Components Library |
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI | | [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro | | [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Online theme preview built on Vant UI | | [vant-theme](https://github.com/Aisen60/vant-theme) | Online theme preview built on Vant UI |

View File

@ -8,7 +8,7 @@
### 介绍 ### 介绍
Vant 是**有赞前端团队**开源的移动端组件库,于 2017 年开源,已持续维护 4 年时间。Vant 对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一。 Vant 是**有赞前端团队**开源的移动端组件库,于 2017 年开源。Vant 对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一。
目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant)、[Vue 3 版本](https://vant-contrib.gitee.io/vant/v3)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/mxdi9i7/vant-react)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。 目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant)、[Vue 3 版本](https://vant-contrib.gitee.io/vant/v3)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/mxdi9i7/vant-react)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。
@ -62,7 +62,7 @@ Vant 3 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一致
| 项目 | 描述 | | 项目 | 描述 |
| --- | --- | | --- | --- |
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 移动端组件库 | | [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 移动端组件库 |
| [mxdi9i7/vant-react](https://github.com/mxdi9i7/vant-react) | 基于 React 和 TS 构建的移动端组件库 | | [rc-ui-lib](https://github.com/rancui/rc-ui-lib) | 基于 Vant 的 React 版本移动端 UI 组件库 |
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 | | [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 | | [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 | | [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 |

View File

@ -99,7 +99,14 @@ If you are using vite, please use [vite-plugin-style-import](https://github.com/
#### 1. Install Plugin #### 1. Install Plugin
```bash ```bash
npm i vite-plugin-style-import@1.2.0 -D # with npm
npm i vite-plugin-style-import -D
# with yarn
yarn add vite-plugin-style-import -D
# with pnpm
pnpm add vite-plugin-style-import -D
``` ```
#### 2. Configure Plugin #### 2. Configure Plugin
@ -108,19 +115,13 @@ Configure the plugin in the `vite.config.js` file:
```js ```js
import vue from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue';
import styleImport from 'vite-plugin-style-import'; import styleImport, { VantResolve } from 'vite-plugin-style-import';
export default { export default {
plugins: [ plugins: [
vue(), vue(),
styleImport({ styleImport({
libs: [ resolves: [VantResolve()],
{
libraryName: 'vant',
esModule: true,
resolveStyle: (name) => `vant/es/${name}/style/index`,
},
],
}), }),
], ],
}; };

View File

@ -100,7 +100,14 @@ pnpm add vant@3
#### 1. 安装插件 #### 1. 安装插件
```bash ```bash
npm i vite-plugin-style-import@1.2.0 -D # 通过 npm 安装
npm i vite-plugin-style-import -D
# 通过 yarn 安装
yarn add vite-plugin-style-import -D
# 通过 pnpm 安装
pnpm add vite-plugin-style-import -D
``` ```
#### 2. 配置插件 #### 2. 配置插件
@ -109,19 +116,13 @@ npm i vite-plugin-style-import@1.2.0 -D
```js ```js
import vue from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue';
import styleImport from 'vite-plugin-style-import'; import styleImport, { VantResolve } from 'vite-plugin-style-import';
export default { export default {
plugins: [ plugins: [
vue(), vue(),
styleImport({ styleImport({
libs: [ resolves: [VantResolve()],
{
libraryName: 'vant',
esModule: true,
resolveStyle: (name) => `vant/es/${name}/style/index`,
},
],
}), }),
], ],
}; };

View File

@ -4,6 +4,21 @@
Vant provide some built-in composition APIs, you can directly use these APIs for development. Vant provide some built-in composition APIs, you can directly use these APIs for development.
### Install
Although `@vant/use` is already included in Vant's dependencies, it is still recommended to install this package explicitly:
```shell
# with npm
npm i @vant/use
# with yarn
yarn add @vant/use
# with pnpm
pnpm add @vant/use
```
### Demo ### Demo
```js ```js

View File

@ -2,7 +2,22 @@
### 介绍 ### 介绍
Vant 内置了一系列的组合式 API对于安装了 `vant` 的项目,可以直接使用这些 API 进行开发。 Vant 底层依赖了 `@vant/use` 包,其中内置了一系列的组合式 API。对于使用了 Vant 的项目,可以复用这些 API 进行开发。
### 安装
虽然 Vant 的依赖中已经包含了 `@vant/use`,但我们仍然推荐显式地安装它:
```shell
# with npm
npm i @vant/use
# with yarn
yarn add @vant/use
# with pnpm
pnpm add @vant/use
```
### 示例 ### 示例

View File

@ -1,9 +1,9 @@
{ {
"name": "vant", "name": "vant",
"version": "3.3.6", "version": "3.4.2",
"description": "Mobile UI Components built on Vue", "description": "Mobile UI Components built on Vue",
"main": "lib/vant.cjs.js", "main": "lib/vant.cjs.js",
"module": "lib/vant.es.js", "module": "es/index.js",
"style": "lib/index.css", "style": "lib/index.css",
"typings": "lib/index.d.ts", "typings": "lib/index.d.ts",
"unpkg": "lib/vant.min.js", "unpkg": "lib/vant.min.js",
@ -14,11 +14,11 @@
"import": "./lib/ssr.mjs", "import": "./lib/ssr.mjs",
"require": "./lib/ssr.js" "require": "./lib/ssr.js"
}, },
"import": "./lib/vant.es.js", "import": "./es/index.js",
"require": "./lib/vant.cjs.js", "require": "./lib/vant.cjs.js",
"types": "./lib/index.d.ts" "types": "./lib/index.d.ts"
}, },
"./es": "./lib/vant.es.js", "./es": "./es/index.js",
"./lib": "./lib/vant.cjs.js", "./lib": "./lib/vant.cjs.js",
"./es/": "./es/", "./es/": "./es/",
"./lib/": "./lib/", "./lib/": "./lib/",
@ -75,11 +75,10 @@
"@vant/area-data": "^1.1.3", "@vant/area-data": "^1.1.3",
"@vant/cli": "workspace:*", "@vant/cli": "workspace:*",
"@vant/eslint-config": "workspace:*", "@vant/eslint-config": "workspace:*",
"@vue/compiler-sfc": "^3.2.20", "@vue/runtime-core": "^3.2.27",
"@vue/runtime-core": "^3.2.20",
"@vue/test-utils": "^2.0.0-rc.16", "@vue/test-utils": "^2.0.0-rc.16",
"typescript": "~4.5.2", "typescript": "~4.5.2",
"vue": "^3.2.20", "vue": "^3.2.27",
"vue-router": "^4.0.12" "vue-router": "^4.0.12"
}, },
"sideEffects": [ "sideEffects": [

View File

@ -1,4 +1,9 @@
import { computed, PropType, defineComponent, ExtractPropTypes } from 'vue'; import {
computed,
defineComponent,
type PropType,
type ExtractPropTypes,
} from 'vue';
import { extend, createNamespace } from '../utils'; import { extend, createNamespace } from '../utils';
import { ACTION_BAR_KEY } from '../action-bar/ActionBar'; import { ACTION_BAR_KEY } from '../action-bar/ActionBar';

View File

@ -4,3 +4,9 @@ import _ActionBarButton from './ActionBarButton';
export const ActionBarButton = withInstall(_ActionBarButton); export const ActionBarButton = withInstall(_ActionBarButton);
export default ActionBarButton; export default ActionBarButton;
export type { ActionBarButtonProps } from './ActionBarButton'; export type { ActionBarButtonProps } from './ActionBarButton';
declare module 'vue' {
export interface GlobalComponents {
VanActionBarButton: typeof ActionBarButton;
}
}

View File

@ -1,4 +1,4 @@
import { defineComponent, ExtractPropTypes } from 'vue'; import { defineComponent, type PropType, type ExtractPropTypes } from 'vue';
import { extend, createNamespace, unknownProp, numericProp } from '../utils'; import { extend, createNamespace, unknownProp, numericProp } from '../utils';
import { ACTION_BAR_KEY } from '../action-bar/ActionBar'; import { ACTION_BAR_KEY } from '../action-bar/ActionBar';
@ -8,7 +8,7 @@ import { useRoute, routeProps } from '../composables/use-route';
// Components // Components
import { Icon } from '../icon'; import { Icon } from '../icon';
import { Badge } from '../badge'; import { Badge, type BadgeProps } from '../badge';
const [name, bem] = createNamespace('action-bar-icon'); const [name, bem] = createNamespace('action-bar-icon');
@ -19,6 +19,7 @@ const actionBarIconProps = extend({}, routeProps, {
color: String, color: String,
badge: numericProp, badge: numericProp,
iconClass: unknownProp, iconClass: unknownProp,
badgeProps: Object as PropType<Partial<BadgeProps>>,
iconPrefix: String, iconPrefix: String,
}); });
@ -35,15 +36,17 @@ export default defineComponent({
useParent(ACTION_BAR_KEY); useParent(ACTION_BAR_KEY);
const renderIcon = () => { const renderIcon = () => {
const { dot, badge, icon, color, iconClass, iconPrefix } = props; const { dot, badge, icon, color, iconClass, badgeProps, iconPrefix } =
props;
if (slots.icon) { if (slots.icon) {
return ( return (
<Badge <Badge
v-slots={{ default: slots.icon }} v-slots={{ default: slots.icon }}
dot={dot} dot={dot}
content={badge}
class={bem('icon')} class={bem('icon')}
content={badge}
{...badgeProps}
/> />
); );
} }
@ -56,6 +59,7 @@ export default defineComponent({
badge={badge} badge={badge}
color={color} color={color}
class={[bem('icon'), iconClass]} class={[bem('icon'), iconClass]}
badgeProps={badgeProps}
classPrefix={iconPrefix} classPrefix={iconPrefix}
/> />
); );

View File

@ -4,3 +4,9 @@ import _ActionBarIcon from './ActionBarIcon';
export const ActionBarIcon = withInstall(_ActionBarIcon); export const ActionBarIcon = withInstall(_ActionBarIcon);
export default ActionBarIcon; export default ActionBarIcon;
export type { ActionBarIconProps } from './ActionBarIcon'; export type { ActionBarIconProps } from './ActionBarIcon';
declare module 'vue' {
export interface GlobalComponents {
VanActionBarIcon: typeof ActionBarIcon;
}
}

View File

@ -59,3 +59,17 @@ test('should render icon slot with dot correctly', () => {
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot();
}); });
test('should render badge-props prop correctly', async () => {
const wrapper = mount(ActionBarIcon, {
props: {
badge: 1,
badgeProps: {
color: 'blue',
},
},
});
const badge = wrapper.find('.van-badge');
expect(badge.style.backgroundColor).toEqual('blue');
});

View File

@ -1,4 +1,4 @@
import { defineComponent, ExtractPropTypes } from 'vue'; import { defineComponent, type ExtractPropTypes } from 'vue';
import { truthProp, createNamespace } from '../utils'; import { truthProp, createNamespace } from '../utils';
import { useChildren } from '@vant/use'; import { useChildren } from '@vant/use';

View File

@ -102,7 +102,8 @@ Use `badge` prop to show badge in icon.
| icon-prefix `v3.0.17` | Icon className prefix | _string_ | `van-icon` | | icon-prefix `v3.0.17` | Icon className prefix | _string_ | `van-icon` |
| dot | Whether to show red dot | _boolean_ | - | | dot | Whether to show red dot | _boolean_ | - |
| badge | Content of the badge | _number \| string_ | - | | badge | Content of the badge | _number \| string_ | - |
| url | Link | _string_ | - | | badge-props `v3.2.8` | Props of Badgesee [Badge - props](#/en-US/badge#props) | _BadgeProps_ | - |
| url | Link URL | _string_ | - |
| to | Target route of the link, same as to of vue-router | _string \| object_ | - | | to | Target route of the link, same as to of vue-router | _string \| object_ | - |
| replace | If true, the navigation will not leave a history record | _boolean_ | `false` | | replace | If true, the navigation will not leave a history record | _boolean_ | `false` |
@ -115,7 +116,7 @@ Use `badge` prop to show badge in icon.
| color | Button color, support linear-gradient | _string_ | - | | color | Button color, support linear-gradient | _string_ | - |
| icon | Left Icon | _string_ | - | | icon | Left Icon | _string_ | - |
| disabled | Whether to disable button | _boolean_ | `false` | | disabled | Whether to disable button | _boolean_ | `false` |
| loading | Whether show loading status | _boolean_ | `false` | | loading | Whether to show loading status | _boolean_ | `false` |
| url | Link | _string_ | - | | url | Link | _string_ | - |
| to | Target route of the link, same as to of vue-router | _string \| object_ | - | | to | Target route of the link, same as to of vue-router | _string \| object_ | - |
| replace | If true, the navigation will not leave a history record | _boolean_ | `false` | | replace | If true, the navigation will not leave a history record | _boolean_ | `false` |

View File

@ -106,6 +106,7 @@ export default {
| icon-prefix `v3.0.17` | 图标类名前缀,等同于 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` | | icon-prefix `v3.0.17` | 图标类名前缀,等同于 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` |
| dot | 是否显示图标右上角小红点 | _boolean_ | `false` | | dot | 是否显示图标右上角小红点 | _boolean_ | `false` |
| badge | 图标右上角徽标的内容 | _number \| string_ | - | | badge | 图标右上角徽标的内容 | _number \| string_ | - |
| badge-props `v3.2.8` | 自定义徽标的属性,传入的对象会被透传给 [Badge 组件的 props](#/zh-CN/badge#props) | _BadgeProps_ | - |
| url | 点击后跳转的链接地址 | _string_ | - | | url | 点击后跳转的链接地址 | _string_ | - |
| to | 点击后跳转的目标路由对象,等同于 vue-router 的 [to 属性](https://router.vuejs.org/zh/api/#to) | _string \| object_ | - | | to | 点击后跳转的目标路由对象,等同于 vue-router 的 [to 属性](https://router.vuejs.org/zh/api/#to) | _string \| object_ | - |
| replace | 是否在跳转时替换当前页面历史 | _boolean_ | `false` | | replace | 是否在跳转时替换当前页面历史 | _boolean_ | `false` |
@ -117,7 +118,7 @@ export default {
| text | 按钮文字 | _string_ | - | | text | 按钮文字 | _string_ | - |
| type | 按钮类型,可选值为 `primary` `info` `warning` `danger` | _string_ | `default` | | type | 按钮类型,可选值为 `primary` `info` `warning` `danger` | _string_ | `default` |
| color | 按钮颜色,支持传入 `linear-gradient` 渐变色 | _string_ | - | | color | 按钮颜色,支持传入 `linear-gradient` 渐变色 | _string_ | - |
| icon | 左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - | | icon | 左侧图标名称或图片链接,等同于 Icon 组件的 [name 属性](#/zh-CN/icon#props) | _string_ | - |
| disabled | 是否禁用按钮 | _boolean_ | `false` | | disabled | 是否禁用按钮 | _boolean_ | `false` |
| loading | 是否显示为加载状态 | _boolean_ | `false` | | loading | 是否显示为加载状态 | _boolean_ | `false` |
| url | 点击后跳转的链接地址 | _string_ | - | | url | 点击后跳转的链接地址 | _string_ | - |

View File

@ -4,3 +4,9 @@ import _ActionBar from './ActionBar';
export const ActionBar = withInstall(_ActionBar); export const ActionBar = withInstall(_ActionBar);
export default ActionBar; export default ActionBar;
export type { ActionBarProps } from './ActionBar'; export type { ActionBarProps } from './ActionBar';
declare module 'vue' {
export interface GlobalComponents {
VanActionBar: typeof ActionBar;
}
}

View File

@ -1,4 +1,4 @@
import { nextTick, defineComponent, ExtractPropTypes } from 'vue'; import { nextTick, defineComponent, type ExtractPropTypes } from 'vue';
// Utils // Utils
import { import {
@ -94,18 +94,23 @@ export default defineComponent({
} }
}; };
const renderOption = (item: ActionSheetAction, index: number) => { const renderActionContent = (action: ActionSheetAction, index: number) => {
const { name, color, subname, loading, callback, disabled, className } = if (action.loading) {
item; return <Loading class={bem('loading-icon')} />;
}
const Content = loading ? ( if (slots.action) {
<Loading class={bem('loading-icon')} /> return slots.action({ action, index });
) : ( }
[
<span class={bem('name')}>{name}</span>, return [
subname && <div class={bem('subname')}>{subname}</div>, <span class={bem('name')}>{action.name}</span>,
] action.subname && <div class={bem('subname')}>{action.subname}</div>,
); ];
};
const renderAction = (action: ActionSheetAction, index: number) => {
const { color, loading, callback, disabled, className } = action;
const onClick = () => { const onClick = () => {
if (disabled || loading) { if (disabled || loading) {
@ -113,14 +118,14 @@ export default defineComponent({
} }
if (callback) { if (callback) {
callback(item); callback(action);
} }
if (props.closeOnClickAction) { if (props.closeOnClickAction) {
updateShow(false); updateShow(false);
} }
nextTick(() => emit('select', item, index)); nextTick(() => emit('select', action, index));
}; };
return ( return (
@ -130,7 +135,7 @@ export default defineComponent({
class={[bem('item', { loading, disabled }), className]} class={[bem('item', { loading, disabled }), className]}
onClick={onClick} onClick={onClick}
> >
{Content} {renderActionContent(action, index)}
</button> </button>
); );
}; };
@ -154,7 +159,7 @@ export default defineComponent({
{renderHeader()} {renderHeader()}
{renderDescription()} {renderDescription()}
<div class={bem('content')}> <div class={bem('content')}>
{props.actions.map(renderOption)} {props.actions.map(renderAction)}
{slots.default?.()} {slots.default?.()}
</div> </div>
{renderCancel()} {renderCancel()}

View File

@ -218,11 +218,12 @@ export default {
### Slots ### Slots
| Name | Description | | Name | Description | SlotProps |
| ---------------- | ------------------------------------ | | --- | --- | --- |
| default | Custom content | | default | Custom content |
| description | Custom description above the options | | description | Custom description above the options |
| cancel `v3.0.10` | Custom the content of cancel button | | cancel `v3.0.10` | Custom the content of cancel button |
| action `v3.4.0` | Custom the content of action | _{ action: ActionSheetAction, index: number }_ |
### Types ### Types

View File

@ -187,7 +187,7 @@ export default {
| cancel-text | 取消按钮文字 | _string_ | - | | cancel-text | 取消按钮文字 | _string_ | - |
| description | 选项上方的描述信息 | _string_ | - | | description | 选项上方的描述信息 | _string_ | - |
| closeable | 是否显示关闭图标 | _boolean_ | `true` | | closeable | 是否显示关闭图标 | _boolean_ | `true` |
| close-icon | 关闭[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `cross` | | close-icon | 关闭图标名称或图片链接,等同于 Icon 组件的 [name 属性](#/zh-CN/icon#props) | _string_ | `cross` |
| duration | 动画时长,单位秒,设置为 0 可以禁用动画 | _number \| string_ | `0.3` | | duration | 动画时长,单位秒,设置为 0 可以禁用动画 | _number \| string_ | `0.3` |
| round | 是否显示圆角 | _boolean_ | `true` | | round | 是否显示圆角 | _boolean_ | `true` |
| overlay | 是否显示遮罩层 | _boolean_ | `true` | | overlay | 是否显示遮罩层 | _boolean_ | `true` |
@ -230,11 +230,12 @@ export default {
### Slots ### Slots
| 名称 | 说明 | | 名称 | 说明 | 参数 |
| ---------------- | -------------------- | | --- | --- | --- |
| default | 自定义面板的展示内容 | | default | 自定义面板的展示内容 | - |
| description | 自定义描述文案 | | description | 自定义描述文案 | - |
| cancel `v3.0.10` | 自定义取消按钮内容 | | cancel `v3.0.10` | 自定义取消按钮内容 | - |
| action `v3.4.0` | 自定义选项内容 | _{ action: ActionSheetAction, index: number }_ |
### 类型定义 ### 类型定义

View File

@ -4,3 +4,9 @@ import _ActionSheet from './ActionSheet';
export const ActionSheet = withInstall(_ActionSheet); export const ActionSheet = withInstall(_ActionSheet);
export default ActionSheet; export default ActionSheet;
export type { ActionSheetProps, ActionSheetAction } from './ActionSheet'; export type { ActionSheetProps, ActionSheetAction } from './ActionSheet';
declare module 'vue' {
export interface GlobalComponents {
VanActionSheet: typeof ActionSheet;
}
}

View File

@ -5,6 +5,14 @@ exports[`should allow to custom close icon with closeIcon prop 1`] = `
</i> </i>
`; `;
exports[`should render action slot correctly 1`] = `
<button type="button"
class="van-action-sheet__item"
>
name: Option, index: 0
</button>
`;
exports[`should render cancel slot correctly 1`] = ` exports[`should render cancel slot correctly 1`] = `
<button type="button" <button type="button"
class="van-action-sheet__cancel" class="van-action-sheet__cancel"

View File

@ -13,7 +13,7 @@ test('should emit select event after clicking option', async () => {
wrapper.find('.van-action-sheet__item').trigger('click'); wrapper.find('.van-action-sheet__item').trigger('click');
await nextTick(); await nextTick();
expect(wrapper.emitted('select')!.length).toEqual(1); expect(wrapper.emitted('select')).toHaveLength(1);
expect(wrapper.emitted('select')![0]).toEqual([ expect(wrapper.emitted('select')![0]).toEqual([
{ {
name: 'Option', name: 'Option',
@ -71,7 +71,7 @@ test('should emit cancel event after clicking cancel button', () => {
}); });
wrapper.find('.van-action-sheet__cancel').trigger('click'); wrapper.find('.van-action-sheet__cancel').trigger('click');
expect(wrapper.emitted('cancel')!.length).toEqual(1); expect(wrapper.emitted('cancel')).toHaveLength(1);
}); });
test('should render subname correctly', () => { test('should render subname correctly', () => {
@ -225,7 +225,7 @@ test('should close after clicking option if close-on-click-action prop is true',
const option = wrapper.find('.van-action-sheet__item'); const option = wrapper.find('.van-action-sheet__item');
option.trigger('click'); option.trigger('click');
expect(wrapper.emitted('update:show')!.length).toEqual(1); expect(wrapper.emitted('update:show')).toHaveLength(1);
expect(wrapper.emitted('update:show')![0]).toEqual([false]); expect(wrapper.emitted('update:show')![0]).toEqual([false]);
}); });
@ -261,3 +261,17 @@ test('should allow to control safe-area with safe-area-inset-bottom prop', async
'van-safe-area-bottom' 'van-safe-area-bottom'
); );
}); });
test('should render action slot correctly', () => {
const wrapper = mount(ActionSheet, {
props: {
show: true,
actions: [{ name: 'Option' }],
},
slots: {
action: ({ action, index }) => `name: ${action.name}, index: ${index}`,
},
});
expect(wrapper.find('.van-action-sheet__item').html()).toMatchSnapshot();
});

View File

@ -4,9 +4,9 @@ import {
computed, computed,
nextTick, nextTick,
reactive, reactive,
PropType,
defineComponent, defineComponent,
ExtractPropTypes, type PropType,
type ExtractPropTypes,
} from 'vue'; } from 'vue';
// Utils // Utils

View File

@ -1,4 +1,4 @@
import { PropType, ref, defineComponent } from 'vue'; import { ref, defineComponent, type PropType } from 'vue';
// Utils // Utils
import { createNamespace, numericProp } from '../utils'; import { createNamespace, numericProp } from '../utils';

View File

@ -9,3 +9,9 @@ export type {
AddressEditInstance, AddressEditInstance,
AddressEditSearchItem, AddressEditSearchItem,
} from './types'; } from './types';
declare module 'vue' {
export interface GlobalComponents {
VanAddressEdit: typeof AddressEdit;
}
}

View File

@ -1,4 +1,4 @@
import { defineComponent, ExtractPropTypes } from 'vue'; import { defineComponent, type ExtractPropTypes } from 'vue';
// Utils // Utils
import { import {

View File

@ -1,4 +1,4 @@
import { PropType, defineComponent } from 'vue'; import { defineComponent, type PropType } from 'vue';
// Utils // Utils
import { createNamespace, extend, makeRequiredProp } from '../utils'; import { createNamespace, extend, makeRequiredProp } from '../utils';

View File

@ -92,7 +92,7 @@
right: var(--van-padding-md); right: var(--van-padding-md);
color: var(--van-gray-6); color: var(--van-gray-6);
font-size: var(--van-address-list-edit-icon-size); font-size: var(--van-address-list-edit-icon-size);
transform: translate(0, -50%); transform: translateY(-50%);
} }
.van-cell { .van-cell {

View File

@ -5,3 +5,9 @@ export const AddressList = withInstall(_AddressList);
export default AddressList; export default AddressList;
export type { AddressListProps } from './AddressList'; export type { AddressListProps } from './AddressList';
export type { AddressListAddress } from './AddressListItem'; export type { AddressListAddress } from './AddressListItem';
declare module 'vue' {
export interface GlobalComponents {
VanAddressList: typeof AddressList;
}
}

View File

@ -4,10 +4,10 @@ import {
computed, computed,
reactive, reactive,
nextTick, nextTick,
PropType,
onMounted, onMounted,
defineComponent, defineComponent,
ExtractPropTypes, type PropType,
type ExtractPropTypes,
} from 'vue'; } from 'vue';
// Utils // Utils
@ -188,15 +188,15 @@ export default defineComponent({
}; };
const setValues = () => { const setValues = () => {
let code = state.code || getDefaultCode();
const picker = pickerRef.value; const picker = pickerRef.value;
const province = getColumnValues('province');
const city = getColumnValues('city', code.slice(0, 2));
if (!picker) { if (!picker) {
return; return;
} }
let code = state.code || getDefaultCode();
const province = getColumnValues('province');
const city = getColumnValues('city', code.slice(0, 2));
picker.setColumnValues(0, province); picker.setColumnValues(0, province);
picker.setColumnValues(1, city); picker.setColumnValues(1, city);

View File

@ -5,3 +5,9 @@ export const Area = withInstall(_Area);
export default Area; export default Area;
export type { AreaProps } from './Area'; export type { AreaProps } from './Area';
export type { AreaList, AreaInstance, AreaColumnOption } from './types'; export type { AreaList, AreaInstance, AreaColumnOption } from './types';
declare module 'vue' {
export interface GlobalComponents {
VanArea: typeof Area;
}
}

View File

@ -36,14 +36,6 @@ exports[`should render columns-top、columns-bottom slot correctly 1`] = `
> >
</ul> </ul>
</div> </div>
<div class="van-picker__mask"
style="background-size: 100% 110px;"
>
</div>
<div class="van-hairline-unset--top-bottom van-picker__frame"
style="height: 44px;"
>
</div>
</div> </div>
Bottom Bottom
</div> </div>
@ -130,14 +122,6 @@ exports[`should render two columns when columns-num prop is two 1`] = `
</li> </li>
</ul> </ul>
</div> </div>
<div class="van-picker__mask"
style="background-size: 100% 110px;"
>
</div>
<div class="van-hairline-unset--top-bottom van-picker__frame"
style="height: 44px;"
>
</div>
</div> </div>
</div> </div>
`; `;

View File

@ -116,10 +116,10 @@ test('should render two columns when columns-num prop is two', async () => {
}, },
}); });
expect(wrapper.findAll('.van-picker-column').length).toEqual(3); expect(wrapper.findAll('.van-picker-column')).toHaveLength(3);
await wrapper.setProps({ columnsNum: 2 }); await wrapper.setProps({ columnsNum: 2 });
expect(wrapper.findAll('.van-picker-column').length).toEqual(2); expect(wrapper.findAll('.van-picker-column')).toHaveLength(2);
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot();
}); });

View File

@ -1,9 +1,9 @@
import { import {
computed, computed,
PropType,
CSSProperties,
defineComponent, defineComponent,
ExtractPropTypes, type PropType,
type CSSProperties,
type ExtractPropTypes,
} from 'vue'; } from 'vue';
import { import {
isDef, isDef,

View File

@ -4,3 +4,9 @@ import _Badge from './Badge';
export const Badge = withInstall(_Badge); export const Badge = withInstall(_Badge);
export default Badge; export default Badge;
export type { BadgeProps, BadgePosition } from './Badge'; export type { BadgeProps, BadgePosition } from './Badge';
declare module 'vue' {
export interface GlobalComponents {
VanBadge: typeof Badge;
}
}

View File

@ -1,8 +1,8 @@
import { import {
PropType,
CSSProperties,
defineComponent, defineComponent,
ExtractPropTypes, type PropType,
type CSSProperties,
type ExtractPropTypes,
} from 'vue'; } from 'vue';
// Utils // Utils

View File

@ -126,7 +126,7 @@ app.use(Button);
| round | Whether to be round button | _boolean_ | `false` | | round | Whether to be round button | _boolean_ | `false` |
| square | Whether to be square button | _boolean_ | `false` | | square | Whether to be square button | _boolean_ | `false` |
| disabled | Whether to disable button | _boolean_ | `false` | | disabled | Whether to disable button | _boolean_ | `false` |
| loading | Whether show loading status | _boolean_ | `false` | | loading | Whether to show loading status | _boolean_ | `false` |
| loading-text | Loading text | _string_ | - | | loading-text | Loading text | _string_ | - |
| loading-type | Loading type, can be set to `spinner` | _string_ | `circular` | | loading-type | Loading type, can be set to `spinner` | _string_ | `circular` |
| loading-size | Loading icon size | _number \| string_ | `20px` | | loading-size | Loading icon size | _number \| string_ | `20px` |

View File

@ -138,7 +138,7 @@ app.use(Button);
| size | 尺寸,可选值为 `large` `small` `mini` | _string_ | `normal` | | size | 尺寸,可选值为 `large` `small` `mini` | _string_ | `normal` |
| text | 按钮文字 | _string_ | - | | text | 按钮文字 | _string_ | - |
| color | 按钮颜色,支持传入 `linear-gradient` 渐变色 | _string_ | - | | color | 按钮颜色,支持传入 `linear-gradient` 渐变色 | _string_ | - |
| icon | 左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - | | icon | 左侧图标名称或图片链接,等同于 Icon 组件的 [name 属性](#/zh-CN/icon#props) | _string_ | - |
| icon-prefix | 图标类名前缀,等同于 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` | | icon-prefix | 图标类名前缀,等同于 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` |
| icon-position | 图标展示位置,可选值为 `right` | _string_ | `left` | | icon-position | 图标展示位置,可选值为 `right` | _string_ | `left` |
| tag | 按钮根节点的 HTML 标签 | _string_ | `button` | | tag | 按钮根节点的 HTML 标签 | _string_ | `button` |

View File

@ -10,3 +10,9 @@ export type {
ButtonNativeType, ButtonNativeType,
ButtonIconPosition, ButtonIconPosition,
} from './types'; } from './types';
declare module 'vue' {
export interface GlobalComponents {
VanButton: typeof Button;
}
}

View File

@ -5,7 +5,7 @@ test('should emit click event', () => {
const wrapper = mount(Button); const wrapper = mount(Button);
wrapper.trigger('click'); wrapper.trigger('click');
expect(wrapper.emitted('click')!.length).toEqual(1); expect(wrapper.emitted('click')).toHaveLength(1);
}); });
test('should not emit click event when disabled', () => { test('should not emit click event when disabled', () => {

View File

@ -2,10 +2,10 @@ import {
ref, ref,
watch, watch,
computed, computed,
PropType,
TeleportProps,
defineComponent, defineComponent,
ExtractPropTypes, type PropType,
type TeleportProps,
type ExtractPropTypes,
} from 'vue'; } from 'vue';
// Utils // Utils
@ -406,7 +406,12 @@ export default defineComponent({
); );
if (disabledDay) { if (disabledDay) {
select([startDay, getPrevDay(disabledDay)]); const endDay = getPrevDay(disabledDay);
if (compareDay(startDay, endDay) === -1) {
select([startDay, endDay]);
} else {
select([date]);
}
} else { } else {
select([startDay, date], true); select([startDay, date], true);
} }

View File

@ -1,4 +1,9 @@
import { computed, CSSProperties, PropType, defineComponent } from 'vue'; import {
computed,
defineComponent,
type PropType,
type CSSProperties,
} from 'vue';
import { makeNumberProp, createNamespace, makeRequiredProp } from '../utils'; import { makeNumberProp, createNamespace, makeRequiredProp } from '../utils';
import { bem } from './utils'; import { bem } from './utils';
import type { CalendarDayItem } from './types'; import type { CalendarDayItem } from './types';

View File

@ -1,9 +1,9 @@
import { import {
ref, ref,
computed, computed,
PropType,
defineComponent, defineComponent,
ExtractPropTypes, type PropType,
type ExtractPropTypes,
} from 'vue'; } from 'vue';
// Utils // Utils

View File

@ -10,3 +10,9 @@ export type {
CalendarDayType, CalendarDayType,
CalendarInstance, CalendarInstance,
} from './types'; } from './types';
declare module 'vue' {
export interface GlobalComponents {
VanCalendar: typeof Calendar;
}
}

View File

@ -1,4 +1,4 @@
import { defineComponent, ExtractPropTypes } from 'vue'; import { defineComponent, type ExtractPropTypes } from 'vue';
// Utils // Utils
import { isDef, numericProp, makeStringProp, createNamespace } from '../utils'; import { isDef, numericProp, makeStringProp, createNamespace } from '../utils';

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