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 |
| --- | --- |
| [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 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro |
| [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)。
@ -104,7 +104,7 @@ Vant 3 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一致
| 项目 | 描述 |
| --- | --- |
| [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 支付宝小程序版 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 |

View File

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

View File

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

View File

@ -1,12 +1,17 @@
{
"name": "@vant/area-data",
"version": "1.1.3",
"version": "1.2.1",
"description": "Vant 省市区数据",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "rimraf ./lib && tsc",
"release": "pnpm build && npm publish",
"clean": "rimraf ./dist",
"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"
},
"publishConfig": {
@ -20,5 +25,16 @@
},
"bugs": "https://github.com/youzan/vant/issues",
"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: '新北市',
711200: '宜兰县',
711300: '新竹县',
711400: '桃园',
711400: '桃园',
711500: '苗栗县',
711700: '彰化县',
711900: '嘉义县',
@ -1290,8 +1290,8 @@ export const areaList = {
330110: '余杭区',
330111: '富阳区',
330112: '临安区',
330113: '钱塘区',
330114: '临平区',
330113: '临平区',
330114: '钱塘区',
330122: '桐庐县',
330127: '淳安县',
330182: '建德市',

View File

@ -1,8 +1,7 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"target": "ES2019",
"outDir": "./lib",
"outDir": "./dist",
"declaration": true
},
"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],
moduleFileExtensions: ['js', 'jsx', 'vue', 'ts', 'tsx'],
transform: {
'\\.(vue)$': 'vue3-jest',
'\\.(js|jsx|ts|tsx)$': 'babel-jest',
'\\.(js|jsx|ts|tsx|vue)$': '<rootDir>/node_modules/@vant/cli/cjs/jest.transformer.cjs',
},
transformIgnorePatterns: ['/node_modules/(?!(@vant/cli))/'],
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.htmlMeta](#sitehtmlmeta)
- [site.enableVConsole](#siteenablevconsole)
- [Babel](#babel)
- [默认配置](#----)
- [Postcss](#postcss)
- [默认配置](#-----1)
- [browserslist](#browserslist)
@ -337,36 +335,13 @@ module.exports = {
是否在 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.config.js`文件可以对 Postcss 进行配置。
### 默认配置
`vant-cli`中默认的 Postcss 配置如下:
`vant-cli` 中默认的 Postcss 配置如下:
```js
module.exports = {
@ -378,7 +353,7 @@ module.exports = {
## browserslist
推荐在`package.json`文件里添加 browserslist 字段,这个值会被`@babel/preset-env``autoprefixer`用来确定目标浏览器的版本,保证编译后代码的兼容性。
推荐在 `package.json` 文件里添加 browserslist 字段,这个值会被 `autoprefixer` 用来确定目标浏览器的版本,保证编译后代码的兼容性。
在移动端浏览器中使用,可以添加如下配置:

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
import fse from 'fs-extra';
import execa from 'execa';
import { join, relative } from 'path';
import fse from 'fs-extra';
import { clean } from './clean.js';
import { CSS_LANG } from '../common/css.js';
import { ora, consola } from '../common/logger.js';
@ -27,12 +27,13 @@ import {
setModuleEnv,
setBuildTarget,
} from '../common/index.js';
import type { Format } from 'esbuild';
const { remove, copy, readdir, existsSync } = fse;
async function compileFile(filePath: string) {
async function compileFile(filePath: string, format: Format) {
if (isScript(filePath)) {
return compileScript(filePath);
return compileScript(filePath, format);
}
if (isStyle(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);
await Promise.all(
files.map((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() {
setModuleEnv('esmodule');
setBuildTarget('package');
await compileDir(ES_DIR);
await compileDir(ES_DIR, 'esm');
}
async function buildCJSOutputs() {
setModuleEnv('commonjs');
setBuildTarget('package');
await compileDir(LIB_DIR);
await compileDir(LIB_DIR, 'cjs');
}
async function buildTypeDeclarations() {

View File

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

View File

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

View File

@ -1,5 +1,4 @@
import fse from 'fs-extra';
import { get } from 'lodash-es';
import { sep, join } from 'path';
import { SRC_DIR, getVantConfig } from './constant.js';
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 STYLE_REGEXP = /\.(css|less|scss)$/;
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 function removeExt(path: string) {
@ -46,33 +46,14 @@ export function getComponents() {
);
}
export function isDir(dir: string) {
return lstatSync(dir).isDirectory();
}
export function isDemoDir(dir: string) {
return DEMO_REGEXP.test(dir);
}
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);
}
export const isDir = (dir: string) => 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 const isSfc = (path: string) => SFC_REGEXP.test(path);
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);
const camelizeRE = /-(\w)/g;
const pascalizeRE = /(\w)(\w*)/g;
@ -135,7 +116,7 @@ export function smartOutputFile(filePath: string, content: string) {
export function mergeCustomViteConfig(config: InlineConfig) {
const vantConfig = getVantConfig();
const configureVite = get(vantConfig, 'build.configureVite');
const configureVite = vantConfig.build?.configureVite;
if (configureVite) {
return configureVite(config);

View File

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

View File

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

View File

@ -1,36 +1,56 @@
import fse from 'fs-extra';
import babel from '@babel/core';
import esbuild, { type Format } from 'esbuild';
import { sep } from 'path';
import { transformAsync } from '@babel/core';
import { replaceExt } from '../common/index.js';
import { isJsx, replaceExt } from '../common/index.js';
import { replaceCSSImportExt } from '../common/css.js';
import { replaceScriptImportExt } from './get-deps.js';
const { readFileSync, removeSync, outputFileSync } = fse;
export async function compileScript(filePath: string): Promise<void> {
return new Promise((resolve, reject) => {
if (filePath.includes('.d.ts')) {
resolve();
return;
export async function compileScript(
filePath: string,
format: Format
): Promise<void> {
if (filePath.includes('.d.ts')) {
return;
}
let code = readFileSync(filePath, 'utf-8');
if (!filePath.includes(`${sep}style${sep}`)) {
code = replaceCSSImportExt(code);
}
code = replaceScriptImportExt(code, '.vue', '');
if (isJsx(filePath)) {
const babelResult = await babel.transformAsync(code, {
filename: filePath,
babelrc: false,
presets: ['@babel/preset-typescript'],
plugins: [
[
'@vue/babel-plugin-jsx',
{
enableObjectSlots: false,
},
],
],
});
if (babelResult?.code) {
({ code } = babelResult);
}
}
let code = readFileSync(filePath, 'utf-8');
if (!filePath.includes(`${sep}style${sep}`)) {
code = replaceCSSImportExt(code);
}
code = replaceScriptImportExt(code, '.vue', '');
transformAsync(code, { filename: filePath })
.then((result) => {
if (result) {
const jsFilePath = replaceExt(filePath, '.js');
removeSync(filePath);
outputFileSync(jsFilePath, result.code);
resolve();
}
})
.catch(reject);
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 path from 'path';
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';
const { remove, readFileSync, outputFile } = fse;

View File

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

View File

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

View File

@ -1,5 +1,4 @@
import { join } from 'path';
import { get } from 'lodash-es';
import { createRequire } from 'module';
import hljs from 'highlight.js';
import vitePluginMd from 'vite-plugin-md';
@ -82,7 +81,7 @@ function getTitle(config: { title: string; description?: string }) {
}
function getHTMLMeta(vantConfig: any) {
const meta = get(vantConfig, 'site.htmlMeta');
const meta = vantConfig.site?.htmlMeta;
if (meta) {
return Object.keys(meta)
@ -99,8 +98,8 @@ export function getViteConfigForSiteDev(): InlineConfig {
const vantConfig = getVantConfig();
const siteConfig = getSiteConfig(vantConfig);
const title = getTitle(siteConfig);
const baiduAnalytics = get(vantConfig, 'site.baiduAnalytics');
const enableVConsole = isDev() && get(vantConfig, 'site.enableVConsole');
const baiduAnalytics = vantConfig.site?.baiduAnalytics;
const enableVConsole = isDev() && vantConfig.site?.enableVConsole;
return {
root: SITE_SRC_DIR,
@ -136,6 +135,9 @@ export function getViteConfigForSiteDev(): InlineConfig {
data: {
...siteConfig,
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,
enableVConsole,
meta: getHTMLMeta(vantConfig),
@ -159,8 +161,8 @@ export function getViteConfigForSiteDev(): InlineConfig {
export function getViteConfigForSiteProd(): InlineConfig {
const devConfig = getViteConfigForSiteDev();
const vantConfig = getVantConfig();
const outDir = get(vantConfig, 'build.site.outputDir', SITE_DIST_DIR);
const publicPath = get(vantConfig, 'build.site.publicPath', '/');
const outDir = vantConfig.build?.site?.outputDir || SITE_DIST_DIR;
const publicPath = vantConfig.build?.site?.publicPath || '/';
return {
...devConfig,

View File

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

View File

@ -1,5 +1,13 @@
## Changelog
## 1.7.3
- complete https protocol
## 1.7.2
- add cash-o icon
## 1.7.1
- 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 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",
"version": "1.7.1",
"version": "1.7.3",
"description": "vant icons",
"main": "./src/config.js",
"types": "./src/config.d.ts",

View File

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

View File

@ -149,6 +149,7 @@ export default {
'shrink',
'shield-o',
'guide-o',
'cash-o',
],
filled: [
// 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-display: auto;
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'),
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'),
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');
}

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[]) {
const veturTags: VeturTags = {};
tags.forEach(tag => {
tags.forEach((tag) => {
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[]) {
const veturAttributes: VeturAttributes = {};
tags.forEach(tag => {
tags.forEach((tag) => {
if (tag.attributes) {
tag.attributes.forEach(attr => {
let attribute: VeturAttribute = {
tag.attributes.forEach((attr) => {
const attribute: VeturAttribute = {
type: attr.value.type,
description: `${attr.description}, 默认值: ${attr.default}`
}
description: `${attr.description}, Default: ${attr.default}`,
};
if (attr.options.length > 0) {
attribute.options = attr.options
attribute.options = attr.options;
}
veturAttributes[`${tag.name}/${attr.name}`] = attribute;

View File

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

View File

@ -34,7 +34,7 @@
"esbuild": "^0.13.15",
"release-it": "^14.0.2",
"typescript": "~4.5.2",
"vue": "^3.2.20"
"vue": "^3.2.27"
},
"release-it": {
"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
### [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)
`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)
`2021-12-05`
@ -59,15 +148,15 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
**Feature**
- 新增 `package.json` 中的 `exports` 字段 [#9952](https://github.com/issues/9952)
- Tabbar: 支持在 route 模式下匹配子路由 [#9926](https://github.com/issues/9926)
- Tabs: 将 `van-tab__pane-wrapper` 类重命名为 `van-tab__panel-wrapper` [#9951](https://github.com/issues/9951)
- 新增 `package.json` 中的 `exports` 字段 [#9952](https://github.com/youzan/vant/issues/9952)
- Tabbar: 支持在 route 模式下匹配子路由 [#9926](https://github.com/youzan/vant/issues/9926)
- Tabs: 将 `van-tab__pane-wrapper` 类重命名为 `van-tab__panel-wrapper` [#9951](https://github.com/youzan/vant/issues/9951)
**Bug Fixes**
- Calendar: 修复 show-confirm 为 false 时不会限制最大日期范围的问题 [#9948](https://github.com/issues/9948)
- Calendar: 修复 `scrollToDate` 方法无法精确滚动到对应日期的问题 [#9949](https://github.com/issues/9949)
- Swipe: 修复开始滑动时未阻止 touchmove 事件行为的问题 [#9920](https://github.com/issues/9920)
- Calendar: 修复 show-confirm 为 false 时不会限制最大日期范围的问题 [#9948](https://github.com/youzan/vant/issues/9948)
- Calendar: 修复 `scrollToDate` 方法无法精确滚动到对应日期的问题 [#9949](https://github.com/youzan/vant/issues/9949)
- Swipe: 修复开始滑动时未阻止 touchmove 事件行为的问题 [#9920](https://github.com/youzan/vant/issues/9920)
### [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**
- 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)

View File

@ -8,8 +8,8 @@
### Issue 规范
- 遇到问题时,请先确认这个问题是否已经在 issue 中有记录或者已被修复
- 提 issue 时,请用简短的语言描述遇到的问题,并添加出现问题时的环境和复现步骤
- 遇到问题时,请先确认这个问题是否已经在 issue 中有记录或者已被修复
- 提 issue 时,请用简短的语言描述遇到的问题,并添加出现问题时的环境和复现步骤
## 参与开发
@ -71,28 +71,38 @@ src
└─ README.zh-CN.md # 中文文档
```
### 代码规范
在编写代码时,请注意:
- 确保代码可以通过仓库的 ESLint 和 Stylelint 校验。
- 确保代码格式是规范的,使用 prettier 进行代码格式化。
- 确保没有使用超出兼容性范围的 API比如 `async/await`
## 提交 PR
### Pull Request 规范
### 参考指南
如果你是第一次在 GitHub 上提 Pull Request ,可以阅读下面这两篇文章来学习:
- [如何优雅地在 GitHub 上贡献代码](https://segmentfault.com/a/1190000000736629)
- [第一次参与开源](https://github.com/firstcontributions/first-contributions/blob/master/translations/README.chs.md)
#### 规范
### Pull Request 规范
- 如果遇到问题,建议保持你的 PR 足够小。保证一个 PR 只解决一个问题或只添加一个功能
- 当新增组件或者修改原有组件时,记得增加或者修改测试代码,保证代码的稳定
- 在 PR 中请添加合适的描述,并关联相关的 Issue
在提交 Pull Request 时,请注意:
- 如果遇到问题,建议保持你的 PR 足够小。保证一个 PR 只解决单个问题、添加单个功能。
- 当新增组件或者修改原有组件时,记得增加或者修改对应的单元测试,保证代码的稳定。
- 在 PR 中请添加合适的描述,并关联相关的 Issue。
### Pull Request 流程
1. fork 主仓库,如果已经 fork 过,请同步主仓库的最新代码
2. 基于 fork 后仓库的 dev 分支新建一个分支,比如 `feature/button_color`
3. 在新分支上进行开发,开发完成后,提 Pull Request 到主仓库的 dev 分支
4. Pull Request 会在 Review 通过后被合并到主仓库
5. 等待 Vant 发布版本,一般是每周一次
1. fork 主仓库,如果已经 fork 过,请同步主仓库的最新代码
2. 基于 fork 后仓库的 dev 分支新建一个分支,比如 `feature/button_color`
3. 在新分支上进行开发,开发完成后,提 Pull Request 到主仓库的 dev 分支
4. Pull Request 会在 Review 通过后被合并到主仓库
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 |
| --- | --- |
| [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 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro |
| [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)。
@ -62,7 +62,7 @@ Vant 3 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一致
| 项目 | 描述 |
| --- | --- |
| [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 支付宝小程序版 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 |
| [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
```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
@ -108,19 +115,13 @@ Configure the plugin in the `vite.config.js` file:
```js
import vue from '@vitejs/plugin-vue';
import styleImport from 'vite-plugin-style-import';
import styleImport, { VantResolve } from 'vite-plugin-style-import';
export default {
plugins: [
vue(),
styleImport({
libs: [
{
libraryName: 'vant',
esModule: true,
resolveStyle: (name) => `vant/es/${name}/style/index`,
},
],
resolves: [VantResolve()],
}),
],
};

View File

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

View File

@ -4,6 +4,21 @@
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
```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",
"version": "3.3.6",
"version": "3.4.2",
"description": "Mobile UI Components built on Vue",
"main": "lib/vant.cjs.js",
"module": "lib/vant.es.js",
"module": "es/index.js",
"style": "lib/index.css",
"typings": "lib/index.d.ts",
"unpkg": "lib/vant.min.js",
@ -14,11 +14,11 @@
"import": "./lib/ssr.mjs",
"require": "./lib/ssr.js"
},
"import": "./lib/vant.es.js",
"import": "./es/index.js",
"require": "./lib/vant.cjs.js",
"types": "./lib/index.d.ts"
},
"./es": "./lib/vant.es.js",
"./es": "./es/index.js",
"./lib": "./lib/vant.cjs.js",
"./es/": "./es/",
"./lib/": "./lib/",
@ -75,11 +75,10 @@
"@vant/area-data": "^1.1.3",
"@vant/cli": "workspace:*",
"@vant/eslint-config": "workspace:*",
"@vue/compiler-sfc": "^3.2.20",
"@vue/runtime-core": "^3.2.20",
"@vue/runtime-core": "^3.2.27",
"@vue/test-utils": "^2.0.0-rc.16",
"typescript": "~4.5.2",
"vue": "^3.2.20",
"vue": "^3.2.27",
"vue-router": "^4.0.12"
},
"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 { ACTION_BAR_KEY } from '../action-bar/ActionBar';

View File

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

View File

@ -4,3 +4,9 @@ import _ActionBarIcon from './ActionBarIcon';
export const ActionBarIcon = withInstall(_ActionBarIcon);
export default 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();
});
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 { 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` |
| dot | Whether to show red dot | _boolean_ | - |
| 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_ | - |
| 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_ | - |
| icon | Left Icon | _string_ | - |
| 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_ | - |
| 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` |

View File

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

View File

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

View File

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

View File

@ -187,7 +187,7 @@ export default {
| cancel-text | 取消按钮文字 | _string_ | - |
| description | 选项上方的描述信息 | _string_ | - |
| 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` |
| round | 是否显示圆角 | _boolean_ | `true` |
| overlay | 是否显示遮罩层 | _boolean_ | `true` |
@ -230,11 +230,12 @@ export default {
### Slots
| 名称 | 说明 |
| ---------------- | -------------------- |
| default | 自定义面板的展示内容 |
| description | 自定义描述文案 |
| cancel `v3.0.10` | 自定义取消按钮内容 |
| 名称 | 说明 | 参数 |
| --- | --- | --- |
| default | 自定义面板的展示内容 | - |
| description | 自定义描述文案 | - |
| 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 default 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>
`;
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`] = `
<button type="button"
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');
await nextTick();
expect(wrapper.emitted('select')!.length).toEqual(1);
expect(wrapper.emitted('select')).toHaveLength(1);
expect(wrapper.emitted('select')![0]).toEqual([
{
name: 'Option',
@ -71,7 +71,7 @@ test('should emit cancel event after clicking cancel button', () => {
});
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', () => {
@ -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');
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]);
});
@ -261,3 +261,17 @@ test('should allow to control safe-area with safe-area-inset-bottom prop', async
'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,
nextTick,
reactive,
PropType,
defineComponent,
ExtractPropTypes,
type PropType,
type ExtractPropTypes,
} from 'vue';
// Utils

View File

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

View File

@ -9,3 +9,9 @@ export type {
AddressEditInstance,
AddressEditSearchItem,
} 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
import {

View File

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

View File

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

View File

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

View File

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

View File

@ -5,3 +5,9 @@ export const Area = withInstall(_Area);
export default Area;
export type { AreaProps } from './Area';
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>
</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>
Bottom
</div>
@ -130,14 +122,6 @@ exports[`should render two columns when columns-num prop is two 1`] = `
</li>
</ul>
</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>
`;

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 });
expect(wrapper.findAll('.van-picker-column').length).toEqual(2);
expect(wrapper.findAll('.van-picker-column')).toHaveLength(2);
expect(wrapper.html()).toMatchSnapshot();
});

View File

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

View File

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

View File

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

View File

@ -126,7 +126,7 @@ app.use(Button);
| round | Whether to be round button | _boolean_ | `false` |
| square | Whether to be square 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-type | Loading type, can be set to `spinner` | _string_ | `circular` |
| loading-size | Loading icon size | _number \| string_ | `20px` |

View File

@ -138,7 +138,7 @@ app.use(Button);
| size | 尺寸,可选值为 `large` `small` `mini` | _string_ | `normal` |
| text | 按钮文字 | _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-position | 图标展示位置,可选值为 `right` | _string_ | `left` |
| tag | 按钮根节点的 HTML 标签 | _string_ | `button` |

View File

@ -10,3 +10,9 @@ export type {
ButtonNativeType,
ButtonIconPosition,
} 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);
wrapper.trigger('click');
expect(wrapper.emitted('click')!.length).toEqual(1);
expect(wrapper.emitted('click')).toHaveLength(1);
});
test('should not emit click event when disabled', () => {

View File

@ -2,10 +2,10 @@ import {
ref,
watch,
computed,
PropType,
TeleportProps,
defineComponent,
ExtractPropTypes,
type PropType,
type TeleportProps,
type ExtractPropTypes,
} from 'vue';
// Utils
@ -406,7 +406,12 @@ export default defineComponent({
);
if (disabledDay) {
select([startDay, getPrevDay(disabledDay)]);
const endDay = getPrevDay(disabledDay);
if (compareDay(startDay, endDay) === -1) {
select([startDay, endDay]);
} else {
select([date]);
}
} else {
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 { bem } from './utils';
import type { CalendarDayItem } from './types';

View File

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

View File

@ -10,3 +10,9 @@ export type {
CalendarDayType,
CalendarInstance,
} 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
import { isDef, numericProp, makeStringProp, createNamespace } from '../utils';

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