Compare commits

...

27 Commits

Author SHA1 Message Date
neverland
84332ae68f
perf(cli): make jest tests faster (#8453) 2021-04-03 13:24:17 +08:00
neverland
380f33a614
chore: fix circular dependency (#8452) 2021-04-02 15:54:41 +08:00
chenjiahan
b1acf75151 docs(@vant/cli): changelog v3.8.0 2021-04-02 15:17:07 +08:00
chenjiahan
fcd12c42e6 chore: release @vant/cli@3.8.0 2021-04-02 15:11:35 +08:00
chenjiahan
7d590b7fa7 chore: release @vant/markdown-vetur@2.1.0 2021-04-02 15:06:43 +08:00
neverland
98b05eab66
fix(markdown-vetur): extract component name from table title (#8450) 2021-04-02 15:03:37 +08:00
neverland
fb36845d60
test(TreeSelect): update test cases (#8449) 2021-04-02 10:39:25 +08:00
neverland
74e19f55d1
chore: adjust some code (#8446) 2021-04-02 10:19:33 +08:00
neverland
65185069bf
feat(CollapseItem): add readonly prop (#8445) 2021-04-01 20:41:56 +08:00
neverland
b594ab1192
test(Sticky): typing (#8444) 2021-04-01 16:04:39 +08:00
neverland
aab3646972
test(ImagePreview): fix snapshot (#8443) 2021-04-01 10:32:34 +08:00
neverland
96ae24496e
feat(Search): add error-message prop (#8442) 2021-04-01 10:19:50 +08:00
neverland
522ce16159
feat(Search): add formatter、format-trigger prop (#8441) 2021-04-01 10:04:55 +08:00
neverland
d1196f885d
docs(Field): improve formatter prop typing (#8440) 2021-04-01 09:56:41 +08:00
neverland
10d2517581
feat(Search): add clear-icon prop (#8439) 2021-04-01 09:53:54 +08:00
neverland
2a065f85ef
feat(Field): add clear-icon prop (#8438) 2021-04-01 09:51:00 +08:00
dependabot[bot]
d51db70789
chore(deps): bump y18n from 4.0.0 to 4.0.1 (#8436)
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-31 08:59:23 +08:00
nemo-shen
5eeaa2dd9b
test(DropdownMenu): test cases (#8425)
* test(DropdownMenu): test cases

* test(DropdownMenu): test cases

Co-authored-by: nemo-shen <1034131477@qq.com>
2021-03-30 16:37:05 +08:00
chenjiahan
c761f04f10 Merge branch 'dev' of https://github.com/youzan/vant into dev 2021-03-30 10:16:58 +08:00
dependabot[bot]
8f7a308e12
chore(deps): bump y18n in /packages/vant-markdown-loader (#8432)
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-30 10:16:31 +08:00
dependabot[bot]
55a5cc763e
chore(deps): bump y18n from 4.0.0 to 4.0.1 in /packages/vant-cli (#8431)
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-30 10:16:03 +08:00
dependabot[bot]
f90d2bdfae
chore(deps): bump y18n from 3.2.1 to 3.2.2 in /packages/vant-icons (#8430)
Bumps [y18n](https://github.com/yargs/y18n) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-30 10:15:43 +08:00
chenjiahan
ccf9aa36af docs(changelog): 3.0.11 2021-03-30 10:14:01 +08:00
chenjiahan
87e7662e12 chore: release 3.0.11 2021-03-30 10:06:44 +08:00
neverland
a3c9111130
docs(DatetimePicke): update demo (#8427) 2021-03-29 19:42:55 +08:00
neverland
62eda87c99
chore: split function call (#8424) 2021-03-29 17:47:24 +08:00
neverland
eec186ac19
feat(Dialog): allow to render JSX message (#8420)
* feat(Dialog): allow to render JSX message

* types: add DialogMessage type
2021-03-29 15:51:02 +08:00
69 changed files with 2043 additions and 1426 deletions

View File

@ -16,6 +16,24 @@ Vant follows [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/).
## Details
### [v3.0.11](https://github.com/youzan/vant/compare/v3.0.10...v3.0.11)
`2021-03-30`
**Feature**
- Cascader: add swipeable prop [#8383](https://github.com/youzan/vant/issues/8383)
- Dialog: add footer slot [#8382](https://github.com/youzan/vant/issues/8382)
- Dialog: allow to render JSX message [#8420](https://github.com/youzan/vant/issues/8420)
- Image: add icon-size prop [#8395](https://github.com/youzan/vant/issues/8395)
- Row: add wrap prop [#8393](https://github.com/youzan/vant/issues/8393)
**Bug Fixes**
- Field: should not reset validation after blured [#8409](https://github.com/youzan/vant/issues/8409)
- Sticky: Element not exist during SSR [#8407](https://github.com/youzan/vant/issues/8407)
- Tabs: incorrect horizontal slip judgment [#8388](https://github.com/youzan/vant/issues/8388)
### [v3.0.10](https://github.com/youzan/vant/compare/v3.0.9...v3.0.10)
`2021-03-19`

View File

@ -16,6 +16,24 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
## 更新内容
### [v3.0.11](https://github.com/youzan/vant/compare/v3.0.10...v3.0.11)
`2021-03-30`
**Feature**
- Cascader: 新增 swipeable 属性 [#8383](https://github.com/youzan/vant/issues/8383)
- Dialog: 新增 footer 插槽 [#8382](https://github.com/youzan/vant/issues/8382)
- Dialog: 支持在 message 中传入 render 函数 [#8420](https://github.com/youzan/vant/issues/8420)
- Image: 新增 icon-size 属性 [#8395](https://github.com/youzan/vant/issues/8395)
- Row: 新增 wrap 属性 [#8393](https://github.com/youzan/vant/issues/8393)
**Bug Fixes**
- Field: 修复在个别情况下错误地清除错误提示的问题 [#8409](https://github.com/youzan/vant/issues/8409)
- Sticky: 修复在 SSR 时提示 Element 不存在的问题 [#8407](https://github.com/youzan/vant/issues/8407)
- Tabs: 修复在 safari 上左滑退出页面时手势判断错误的问题 [#8388](https://github.com/youzan/vant/issues/8388)
### [v3.0.10](https://github.com/youzan/vant/compare/v3.0.9...v3.0.10)
`2021-03-19`

View File

@ -1,6 +1,6 @@
{
"name": "vant",
"version": "3.0.10",
"version": "3.0.11",
"description": "Mobile UI Components built on Vue",
"main": "lib/index.js",
"module": "es/index.js",
@ -65,7 +65,7 @@
"vue": "^3.0.0"
},
"devDependencies": {
"@vant/cli": "^3.7.1",
"@vant/cli": "^3.8.0",
"@vue/compiler-sfc": "^3.0.6",
"prettier": "2.1.0",
"vue": "^3.0.6"

View File

@ -1,5 +1,11 @@
# 更新日志
## v3.8.0
`2021-04-02`
- 修复生成 vetur 配置和 web-types 配置不正确的问题
## v3.7.1
`2021-03-18`

View File

@ -1,6 +1,6 @@
{
"name": "@vant/cli",
"version": "3.7.1",
"version": "3.8.0",
"description": "",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@ -50,7 +50,7 @@
"@types/webpack-dev-server": "^3.11.1",
"@vant/eslint-config": "^3.2.0",
"@vant/markdown-loader": "^4.0.0",
"@vant/markdown-vetur": "^2.0.2",
"@vant/markdown-vetur": "^2.1.0",
"@vant/stylelint-config": "^1.4.2",
"@vant/touch-emulator": "^1.2.0",
"@vue/babel-plugin-jsx": "^1.0.1",

View File

@ -15,15 +15,18 @@ export function test(command: any) {
watch: command.watch,
config: JEST_CONFIG_FILE,
clearCache: command.clearCache,
// make jest tests faster
// see: https://ivantanev.com/make-jest-faster/
maxWorkers: '50%',
} as any;
runCLI(config, [ROOT])
.then(response => {
.then((response) => {
if (!response.results.success && !command.watch) {
process.exit(1);
}
})
.catch(err => {
.catch((err) => {
console.log(err);
if (!command.watch) {

View File

@ -1892,10 +1892,10 @@
markdown-it-anchor "^6.0.0"
transliteration "^2.1.11"
"@vant/markdown-vetur@^2.0.2":
version "2.0.2"
resolved "https://registry.npm.taobao.org/@vant/markdown-vetur/download/@vant/markdown-vetur-2.0.2.tgz#8e6be188952a2c4b0e1d626bf93f47f84ab0f22d"
integrity sha1-jmvhiJUqLEsOHWJr+T9H+Eqw8i0=
"@vant/markdown-vetur@^2.1.0":
version "2.1.0"
resolved "https://registry.npm.taobao.org/@vant/markdown-vetur/download/@vant/markdown-vetur-2.1.0.tgz?cache=0&sync_timestamp=1617347165035&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vant%2Fmarkdown-vetur%2Fdownload%2F%40vant%2Fmarkdown-vetur-2.1.0.tgz#cc49ad807dfcccca898562966d64b7a657ca3aad"
integrity sha1-zEmtgH38zMqJhWKWbWS3plfKOq0=
dependencies:
fast-glob "^3.2.2"
fs-extra "^9.0.0"
@ -10892,9 +10892,9 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
version "4.0.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"
integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==
yallist@^4.0.0:
version "4.0.0"

View File

@ -5156,9 +5156,9 @@ xtend@~4.0.0, xtend@~4.0.1:
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
y18n@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
version "3.2.2"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
yallist@^3.0.0, yallist@^3.0.3:
version "3.0.3"

View File

@ -263,9 +263,9 @@ wrap-ansi@^6.2.0:
strip-ansi "^6.0.0"
y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha1-le+U+F7MgdAHwmThkKEg8KPIVms=
version "4.0.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"
integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==
yargs-parser@^18.1.2:
version "18.1.3"

View File

@ -1,6 +1,6 @@
{
"name": "@vant/markdown-vetur",
"version": "2.0.2",
"version": "2.1.0",
"description": "simple parse markdown to vue component description for vetur auto-completion",
"main": "lib/index.js",
"license": "MIT",

View File

@ -1,30 +1,54 @@
/* eslint-disable no-continue */
import { Artical, Articals } from './parser';
import { Articals } from './parser';
import { formatType, removeVersion, toKebabCase } from './utils';
import { VueTag } from './type';
function getComponentName(artical: Artical, tagPrefix: string) {
if (artical.content) {
return tagPrefix + toKebabCase(artical.content.split(' ')[0]);
}
return '';
function formatComponentName(name: string, tagPrefix: string) {
return tagPrefix + toKebabCase(name);
}
export function formatter(articals: Articals, tagPrefix: string = '') {
if (!articals.length) {
return;
function getNameFromTableTitle(tableTitle: string, tagPrefix: string) {
tableTitle = tableTitle.trim();
if (tableTitle.includes(' ')) {
return formatComponentName(tableTitle, tagPrefix).split(' ')[0];
}
}
function findTag(vueTags: VueTag[], name: string) {
const matched = vueTags.find((item) => item.name === name);
if (matched) {
return matched;
}
const tag: VueTag = {
name: getComponentName(articals[0], tagPrefix),
const newTag: VueTag = {
name,
slots: [],
events: [],
attributes: [],
};
const tables = articals.filter(artical => artical.type === 'table');
vueTags.push(newTag);
tables.forEach(item => {
return newTag;
}
export function formatter(
vueTags: VueTag[],
articals: Articals,
tagPrefix = ''
) {
if (!articals.length) {
return;
}
const mainTitle = articals[0].content;
const defaultName = mainTitle
? formatComponentName(mainTitle.split(' ')[0], tagPrefix)
: '';
const tables = articals.filter((artical) => artical.type === 'table');
tables.forEach((item) => {
const { table } = item;
const prevIndex = articals.indexOf(item) - 1;
const prevArtical = articals[prevIndex];
@ -36,7 +60,10 @@ export function formatter(articals: Articals, tagPrefix: string = '') {
const tableTitle = prevArtical.content;
if (tableTitle.includes('Props')) {
table.body.forEach(line => {
const name = getNameFromTableTitle(tableTitle, tagPrefix) || defaultName;
const tag = findTag(vueTags, name);
table.body.forEach((line) => {
const [name, desc, type, defaultVal] = line;
tag.attributes!.push({
name: removeVersion(name),
@ -52,7 +79,10 @@ export function formatter(articals: Articals, tagPrefix: string = '') {
}
if (tableTitle.includes('Events')) {
table.body.forEach(line => {
const name = getNameFromTableTitle(tableTitle, tagPrefix) || defaultName;
const tag = findTag(vueTags, name);
table.body.forEach((line) => {
const [name, desc] = line;
tag.events!.push({
name: removeVersion(name),
@ -63,7 +93,10 @@ export function formatter(articals: Articals, tagPrefix: string = '') {
}
if (tableTitle.includes('Slots')) {
table.body.forEach(line => {
const name = getNameFromTableTitle(tableTitle, tagPrefix) || defaultName;
const tag = findTag(vueTags, name);
table.body.forEach((line) => {
const [name, desc] = line;
tag.slots!.push({
name: removeVersion(name),
@ -72,6 +105,4 @@ export function formatter(articals: Articals, tagPrefix: string = '') {
});
}
});
return tag;
}

View File

@ -11,8 +11,8 @@ import { genVeturTags, genVeturAttributes } from './vetur';
async function readMarkdown(options: Options) {
const mds = await glob(normalizePath(`${options.path}/**/*.md`));
return mds
.filter(md => options.test.test(md))
.map(path => readFileSync(path, 'utf-8'));
.filter((md) => options.test.test(md))
.map((path) => readFileSync(path, 'utf-8'));
}
export async function parseAndWrite(options: Options) {
@ -21,13 +21,16 @@ export async function parseAndWrite(options: Options) {
}
const mds = await readMarkdown(options);
const datas = mds
.map(md => formatter(mdParser(md), options.tagPrefix))
.filter(item => !!item) as VueTag[];
const vueTags: VueTag[] = [];
const webTypes = genWebTypes(datas, options);
const veturTags = genVeturTags(datas);
const veturAttributes = genVeturAttributes(datas);
mds.forEach((md) => {
const parsedMd = mdParser(md);
formatter(vueTags, parsedMd, options.tagPrefix);
});
const webTypes = genWebTypes(vueTags, options);
const veturTags = genVeturTags(vueTags);
const veturAttributes = genVeturAttributes(vueTags);
outputFileSync(
join(options.outputDir, 'tags.json'),

View File

@ -381,15 +381,15 @@ export default defineComponent({
onBlur={onDetailBlur}
onFocus={() => onFocus('addressDetail')}
onInput={onChangeDetail}
onSelect-search={(event: Event) => emit('select-search', event)}
onSelectSearch={(event: Event) => emit('select-search', event)}
/>
{props.showPostal && (
<Field
v-show={!hideBottomFields.value}
v-model={data.postalCode}
type="tel"
maxlength="6"
label={t('postal')}
maxlength="6"
placeholder={t('postal')}
errorMessage={errorInfo.postalCode}
onFocus={() => onFocus('postalCode')}
@ -402,9 +402,9 @@ export default defineComponent({
<Button
block
round
loading={props.isSaving}
type="danger"
text={props.saveButtonText || t('save')}
loading={props.isSaving}
onClick={onSave}
/>
{props.showDelete && (

View File

@ -268,7 +268,7 @@ Set `poppable` to `false`, the calendar will be displayed directly on the page i
| confirm-disabled-text | Confirm button text when disabled | _string_ | `Confirm` |
| first-day-of-week | Set the start day of week | _0-6_ | `0` |
### Poppable Props
### Calendar Poppable Props
Following props are supported when the poppable is true
@ -282,7 +282,7 @@ Following props are supported when the poppable is true
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` |
| teleport | Return the mount node for Calendar | _string \| Element_ | - |
### Range Props
### Calendar Range Props
Following props are supported when the type is range
@ -292,7 +292,7 @@ Following props are supported when the type is range
| range-prompt | Error message when exceeded max range | _string_ | `Choose no more than xx days` |
| allow-same-day | Whether the start and end time of the range is allowed on the same day | _boolean_ | `false` |
### Multiple Props
### Calendar Multiple Props
Following props are supported when the type is multiple

View File

@ -272,7 +272,7 @@ export default {
| confirm-disabled-text | 确认按钮处于禁用状态时的文字 | _string_ | `确定` |
| first-day-of-week | 设置周起始日 | _0-6_ | `0` |
### Poppable Props
### Calendar Poppable Props
当 Canlendar 的 `poppable``true` 时,支持以下 props:
@ -286,7 +286,7 @@ export default {
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` |
| teleport | 指定挂载的节点,[用法示例](#/zh-CN/popup#zhi-ding-gua-zai-wei-zhi) | _string \| Element_ | - |
### Range Props
### Calendar Range Props
当 Canlendar 的 `type``range` 时,支持以下 props:
@ -296,7 +296,7 @@ export default {
| range-prompt | 范围选择超过最多可选天数时的提示文案 | _string_ | `选择天数不能超过 xx 天` |
| allow-same-day | 是否允许日期范围的起止时间为同一天 | _boolean_ | `false` |
### Multiple Props
### Calendar Multiple Props
当 Canlendar 的 `type``multiple` 时,支持以下 props:

View File

@ -2,7 +2,7 @@ import { ref, watch, computed, nextTick, defineComponent } from 'vue';
// Utils
import { cellProps } from '../cell/Cell';
import { createNamespace } from '../utils';
import { createNamespace, pick } from '../utils';
import { COLLAPSE_KEY, CollapseProvide } from '../collapse/Collapse';
// Composables
@ -22,6 +22,7 @@ export default defineComponent({
...cellProps,
name: [Number, String],
disabled: Boolean,
readonly: Boolean,
isLink: {
type: Boolean,
default: true,
@ -94,13 +95,24 @@ export default defineComponent({
};
const onClickTitle = () => {
if (!props.disabled) {
if (!props.disabled && !props.readonly) {
toggle();
}
};
const renderTitle = () => {
const { border, disabled } = props;
const { border, disabled, readonly } = props;
const attrs = pick(
props,
Object.keys(cellProps) as Array<keyof typeof cellProps>
);
if (readonly) {
attrs.isLink = false;
}
if (disabled || readonly) {
attrs.clickable = false;
}
return (
<Cell
@ -116,10 +128,9 @@ export default defineComponent({
expanded: expanded.value,
borderless: !border,
})}
tabindex={disabled ? -1 : 0}
aria-expanded={String(expanded.value)}
onClick={onClickTitle}
{...props}
{...attrs}
/>
);
};

View File

@ -44,10 +44,6 @@
& .van-cell__right-icon {
color: @collapse-item-title-disabled-color;
}
&:active {
background-color: @white;
}
}
}

View File

@ -132,6 +132,7 @@ export default {
| label | Description below the title | _string_ | - |
| border | Whether to show inner border | _boolean_ | `true` |
| disabled | Whether to disabled collapse | _boolean_ | `false` |
| readonly `v3.0.12` | Whether to be readonly | _boolean_ | `false` |
| is-link | Whether to show link icon | _boolean_ | `true` |
| title-class | Title className | _string_ | - |
| value-class | Value className | _string_ | - |

View File

@ -135,6 +135,7 @@ export default {
| border | 是否显示内边框 | _boolean_ | `true` |
| is-link | 是否展示标题栏右侧箭头并开启点击反馈 | _boolean_ | `true` |
| disabled | 是否禁用面板 | _boolean_ | `false` |
| readonly `v3.0.12` | 是否为只读状态,只读状态下无法操作面板 | _boolean_ | `false` |
| title-class | 左侧标题额外类名 | _string_ | - |
| value-class | 右侧内容额外类名 | _string_ | - |
| label-class | 描述信息额外类名 | _string_ | - |

View File

@ -8,7 +8,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="true"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -29,7 +28,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -45,7 +43,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -65,7 +62,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="true"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -86,7 +82,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -102,7 +97,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -122,7 +116,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<div class="van-cell__title">
<span>
@ -134,11 +127,9 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div class="van-collapse-item van-collapse-item--border">
<div class="van-cell van-cell--clickable van-collapse-item__title van-collapse-item__title--disabled"
<div class="van-cell van-collapse-item__title van-collapse-item__title--disabled"
role="button"
tabindex="-1"
aria-expanded="false"
disabled="true"
>
<div class="van-cell__title">
<span>
@ -150,11 +141,9 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div class="van-collapse-item van-collapse-item--border">
<div class="van-cell van-cell--clickable van-collapse-item__title van-collapse-item__title--disabled"
<div class="van-cell van-collapse-item__title van-collapse-item__title--disabled"
role="button"
tabindex="-1"
aria-expanded="false"
disabled="true"
>
<div class="van-cell__title">
<span>
@ -174,7 +163,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<div class="van-cell__title">
Title1
@ -190,7 +178,6 @@ exports[`should render demo and match snapshot 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
<i class="van-badge__wrapper van-icon van-icon-shop-o van-cell__left-icon">
</i>

View File

@ -7,7 +7,6 @@ exports[`should render slots of CollapseItem correctly 1`] = `
role="button"
tabindex="0"
aria-expanded="false"
disabled="false"
>
this is icon
<div class="van-cell__title">

View File

@ -207,3 +207,31 @@ test('should toggle collapse after calling the toggle method in accordion mode',
wrapper.vm.itemA.toggle();
expect(wrapper.vm.active).toEqual('a');
});
test('should be readonly when using readonly prop', async () => {
const wrapper = mount({
data() {
return {
active: [],
};
},
render() {
return (
<Collapse v-model={this.active}>
<CollapseItem title="a" readonly>
content
</CollapseItem>
</Collapse>
);
},
});
const titles = wrapper.findAll('.van-collapse-item__title');
await titles[0].trigger('click');
expect(wrapper.vm.active).toEqual([]);
expect(wrapper.find('.van-collapse-item__title').classes()).not.toContain(
'van-cell--clickable'
);
wrapper.unmount();
});

View File

@ -35,7 +35,7 @@ import { ref } from 'vue';
export default {
setup() {
const currentDate = ref(new Date());
const currentDate = ref(new Date(2021, 0, 17));
return {
minDate: new Date(2020, 0, 1),
maxDate: new Date(2025, 10, 1),

View File

@ -37,7 +37,7 @@ import { ref } from 'vue';
export default {
setup() {
const currentDate = ref(new Date());
const currentDate = ref(new Date(2021, 0, 17));
return {
minDate: new Date(2020, 0, 1),
maxDate: new Date(2025, 10, 1),

View File

@ -120,7 +120,7 @@ export default {
setup() {
const t = useTranslate(i18n);
const value = reactive({
date: null,
date: new Date(2021, 0, 17),
time: '12:00',
datetime: new Date(2020, 0, 1),
datehour: new Date(2020, 0, 1),

View File

@ -22,13 +22,13 @@ exports[`should render demo and match snapshot 1`] = `
style="height: 264px;"
>
<div class="van-picker-column">
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
<ul style="transform: translate3d(0, 66px, 0); transition-duration: 0ms; transition-property: none;"
class="van-picker-column__wrapper"
>
<li role="button"
style="height: 44px;"
tabindex="0"
class="van-picker-column__item van-picker-column__item--selected"
class="van-picker-column__item"
>
<div class="van-ellipsis">
2020
@ -37,7 +37,7 @@ exports[`should render demo and match snapshot 1`] = `
<li role="button"
style="height: 44px;"
tabindex="0"
class="van-picker-column__item"
class="van-picker-column__item van-picker-column__item--selected"
>
<div class="van-ellipsis">
2021
@ -196,13 +196,13 @@ exports[`should render demo and match snapshot 1`] = `
</ul>
</div>
<div class="van-picker-column">
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
<ul style="transform: translate3d(0, -594px, 0); transition-duration: 0ms; transition-property: none;"
class="van-picker-column__wrapper"
>
<li role="button"
style="height: 44px;"
tabindex="0"
class="van-picker-column__item van-picker-column__item--selected"
class="van-picker-column__item"
>
<div class="van-ellipsis">
01
@ -346,7 +346,7 @@ exports[`should render demo and match snapshot 1`] = `
<li role="button"
style="height: 44px;"
tabindex="0"
class="van-picker-column__item"
class="van-picker-column__item van-picker-column__item--selected"
>
<div class="van-ellipsis">
17

View File

@ -2,7 +2,13 @@ import { PropType, reactive, defineComponent } from 'vue';
// Utils
import { callInterceptor, Interceptor } from '../utils/interceptor';
import { createNamespace, addUnit, pick, UnknownProp } from '../utils';
import {
pick,
addUnit,
isFunction,
UnknownProp,
createNamespace,
} from '../utils';
import { BORDER_TOP, BORDER_LEFT } from '../utils/constant';
import { popupSharedProps, popupSharedPropKeys } from '../popup/shared';
@ -16,6 +22,7 @@ const [name, bem, t] = createNamespace('dialog');
export type DialogTheme = 'default' | 'round-button';
export type DialogAction = 'confirm' | 'cancel';
export type DialogMessage = string | (() => JSX.Element);
export type DialogMessageAlign = 'left' | 'center' | 'right';
const popupKeys = [
@ -32,7 +39,7 @@ export default defineComponent({
title: String,
theme: String as PropType<DialogTheme>,
width: [Number, String],
message: String,
message: [String, Function] as PropType<DialogMessage>,
callback: Function as PropType<(action?: DialogAction) => void>,
allowHtml: Boolean,
className: UnknownProp,
@ -119,15 +126,31 @@ export default defineComponent({
}
};
const renderMessage = (hasTitle: boolean) => {
const { message, allowHtml, messageAlign } = props;
const classNames = bem('message', {
'has-title': hasTitle,
[messageAlign as string]: messageAlign,
});
if (allowHtml && typeof message === 'string') {
return <div class={classNames} innerHTML={message} />;
}
return (
<div class={classNames}>
{isFunction(message) ? message() : message}
</div>
);
};
const renderContent = () => {
if (slots.default) {
return <div class={bem('content')}>{slots.default()}</div>;
}
const { title, message, allowHtml, messageAlign } = props;
const { title, message, allowHtml } = props;
if (message) {
const hasTitle = title || slots.title;
const hasTitle = !!(title || slots.title);
return (
<div
// add key to force re-render
@ -135,15 +158,7 @@ export default defineComponent({
key={allowHtml ? 1 : 0}
class={bem('content', { isolated: !hasTitle })}
>
<div
class={bem('message', {
'has-title': hasTitle,
[messageAlign as string]: messageAlign,
})}
{...{
[allowHtml ? 'innerHTML' : 'textContent']: message,
}}
/>
{renderMessage(hasTitle)}
</div>
);
}

View File

@ -142,7 +142,7 @@ export default {
| --- | --- | --- | --- |
| title | Title | _string_ | - |
| width | Dialog width | _number \| string_ | `320px` |
| message | Message | _string_ | - |
| message | Message | _string \| () => JSX.ELement_ | - |
| messageAlign | Message text aligncan be set to `left` `right` | _string_ | `center` |
| theme | Theme stylecan be set to `round-button` | _string_ | `default` |
| className | Custom className | _string \| Array \| object_ | - |
@ -170,7 +170,7 @@ export default {
| v-model:show | Whether to show dialog | _boolean_ | - |
| title | Title | _string_ | - |
| width | Width | _number \| string_ | `320px` |
| message | Message | _string_ | - |
| message | Message | _string \| () => JSX.ELement_ | - |
| message-align | Message aligncan be set to `left` `right` | _string_ | `center` |
| theme | Theme stylecan be set to `round-button` | _string_ | `default` |
| show-confirm-button | Whether to show confirm button | _boolean_ | `true` |

View File

@ -175,7 +175,7 @@ export default {
| --- | --- | --- | --- |
| title | 标题 | _string_ | - |
| width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` |
| message | 文本内容,支持通过 `\n` 换行 | _string_ | - |
| message | 文本内容,支持通过 `\n` 换行 | _string \| () => JSX.ELement_ | - |
| messageAlign | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` |
| theme | 样式风格,可选值为 `round-button` | _string_ | `default` |
| className | 自定义类名 | _string \| Array \| object_ | - |
@ -205,8 +205,8 @@ export default {
| v-model:show | 是否显示弹窗 | _boolean_ | - |
| title | 标题 | _string_ | - |
| width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` |
| message | 文本内容,支持通过 `\n` 换行 | _string_ | - |
| message-align | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` |
| message | 文本内容,支持通过 `\n` 换行 | _string \| () => JSX.ELement_ | - |
| message-align | 内容水平对齐方式,可选值为 `left` `right` | _string_ | `center` |
| theme | 样式风格,可选值为 `round-button` | _string_ | `default` |
| show-confirm-button | 是否展示确认按钮 | _boolean_ | `true` |
| show-cancel-button | 是否展示取消按钮 | _boolean_ | `false` |

View File

@ -0,0 +1,130 @@
import { App, CSSProperties, TeleportProps } from 'vue';
import { inBrowser, ComponentInstance, withInstall } from '../utils';
import { Interceptor } from '../utils/interceptor';
import { mountComponent, usePopupState } from '../utils/mount-component';
import VanDialog, {
DialogTheme,
DialogAction,
DialogMessage,
DialogMessageAlign,
} from './Dialog';
export type DialogOptions = {
title?: string;
width?: string | number;
theme?: DialogTheme;
message?: DialogMessage;
overlay?: boolean;
teleport?: TeleportProps['to'];
className?: unknown;
allowHtml?: boolean;
lockScroll?: boolean;
transition?: string;
beforeClose?: Interceptor;
messageAlign?: DialogMessageAlign;
overlayClass?: string;
overlayStyle?: CSSProperties;
closeOnPopstate?: boolean;
cancelButtonText?: string;
showCancelButton?: boolean;
showConfirmButton?: boolean;
cancelButtonColor?: string;
confirmButtonText?: string;
confirmButtonColor?: string;
closeOnClickOverlay?: boolean;
};
let instance: ComponentInstance;
function initInstance() {
const Wrapper = {
setup() {
const { state, toggle } = usePopupState();
return () => <VanDialog {...{ ...state, 'onUpdate:show': toggle }} />;
},
};
({ instance } = mountComponent(Wrapper));
}
function Dialog(options: DialogOptions) {
/* istanbul ignore if */
if (!inBrowser) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
if (!instance) {
initInstance();
}
instance.open({
...Dialog.currentOptions,
...options,
callback: (action: DialogAction) => {
(action === 'confirm' ? resolve : reject)(action);
},
});
});
}
Dialog.defaultOptions = {
title: '',
width: '',
theme: null,
message: '',
overlay: true,
callback: null,
teleport: 'body',
className: '',
allowHtml: false,
lockScroll: true,
transition: 'van-dialog-bounce',
beforeClose: null,
overlayClass: '',
overlayStyle: undefined,
messageAlign: '',
cancelButtonText: '',
cancelButtonColor: null,
confirmButtonText: '',
confirmButtonColor: null,
showConfirmButton: true,
showCancelButton: false,
closeOnPopstate: true,
closeOnClickOverlay: false,
};
Dialog.currentOptions = {
...Dialog.defaultOptions,
};
Dialog.alert = Dialog;
Dialog.confirm = (options: DialogOptions) =>
Dialog({
showCancelButton: true,
...options,
});
Dialog.close = () => {
if (instance) {
instance.toggle(false);
}
};
Dialog.setDefaultOptions = (options: DialogOptions) => {
Object.assign(Dialog.currentOptions, options);
};
Dialog.resetDefaultOptions = () => {
Dialog.currentOptions = { ...Dialog.defaultOptions };
};
Dialog.install = (app: App) => {
app.use(withInstall<typeof VanDialog>(VanDialog));
app.config.globalProperties.$dialog = Dialog;
};
Dialog.Component = withInstall<typeof VanDialog>(VanDialog);
export { Dialog };

View File

@ -1,131 +1,6 @@
import { App, CSSProperties, TeleportProps } from 'vue';
import { inBrowser, ComponentInstance, withInstall } from '../utils';
import { Interceptor } from '../utils/interceptor';
import { mountComponent, usePopupState } from '../utils/mount-component';
import VanDialog, {
DialogTheme,
DialogAction,
DialogMessageAlign,
} from './Dialog';
export type DialogOptions = {
title?: string;
width?: string | number;
theme?: DialogTheme;
message?: string;
overlay?: boolean;
teleport?: TeleportProps['to'];
className?: unknown;
allowHtml?: boolean;
lockScroll?: boolean;
transition?: string;
beforeClose?: Interceptor;
messageAlign?: DialogMessageAlign;
overlayClass?: string;
overlayStyle?: CSSProperties;
closeOnPopstate?: boolean;
cancelButtonText?: string;
showCancelButton?: boolean;
showConfirmButton?: boolean;
cancelButtonColor?: string;
confirmButtonText?: string;
confirmButtonColor?: string;
closeOnClickOverlay?: boolean;
};
let instance: ComponentInstance;
function initInstance() {
const Wrapper = {
setup() {
const { state, toggle } = usePopupState();
return () => <VanDialog {...{ ...state, 'onUpdate:show': toggle }} />;
},
};
({ instance } = mountComponent(Wrapper));
}
function Dialog(options: DialogOptions) {
/* istanbul ignore if */
if (!inBrowser) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
if (!instance) {
initInstance();
}
instance.open({
...Dialog.currentOptions,
...options,
callback: (action: DialogAction) => {
(action === 'confirm' ? resolve : reject)(action);
},
});
});
}
Dialog.defaultOptions = {
title: '',
width: '',
theme: null,
message: '',
overlay: true,
callback: null,
teleport: 'body',
className: '',
allowHtml: false,
lockScroll: true,
transition: 'van-dialog-bounce',
beforeClose: null,
overlayClass: '',
overlayStyle: undefined,
messageAlign: '',
cancelButtonText: '',
cancelButtonColor: null,
confirmButtonText: '',
confirmButtonColor: null,
showConfirmButton: true,
showCancelButton: false,
closeOnPopstate: true,
closeOnClickOverlay: false,
};
Dialog.currentOptions = {
...Dialog.defaultOptions,
};
Dialog.alert = Dialog;
Dialog.confirm = (options: DialogOptions) =>
Dialog({
showCancelButton: true,
...options,
});
Dialog.close = () => {
if (instance) {
instance.toggle(false);
}
};
Dialog.setDefaultOptions = (options: DialogOptions) => {
Object.assign(Dialog.currentOptions, options);
};
Dialog.resetDefaultOptions = () => {
Dialog.currentOptions = { ...Dialog.defaultOptions };
};
Dialog.install = (app: App) => {
app.use(withInstall<typeof VanDialog>(VanDialog));
app.config.globalProperties.$dialog = Dialog;
};
Dialog.Component = withInstall<typeof VanDialog>(VanDialog);
import { Dialog, DialogOptions } from './function-call';
import type { DialogTheme, DialogMessage, DialogMessageAlign } from './Dialog';
export default Dialog;
export { Dialog };
export type { DialogTheme, DialogMessageAlign };
export type { DialogTheme, DialogMessage, DialogOptions, DialogMessageAlign };

View File

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should allow to render JSX message 1`] = `
<div class="van-dialog__message">
<div>
foo
</div>
</div>
`;

View File

@ -1,6 +1,6 @@
import { createApp } from 'vue';
import { later } from '../../../test';
import { Dialog } from '..';
import { Dialog } from '../function-call';
import DialogComponent from '../Dialog';
test('should update default options when calling setDefaultOptions method', () => {
@ -49,3 +49,17 @@ test('should close dialog after calling Dialog.call', async () => {
'van-dialog-bounce-leave-active'
);
});
test('should allow to render JSX message', async () => {
const wrapper = document.createElement('div');
Dialog.alert({
message: () => <div>foo</div>,
teleport: wrapper,
});
await later();
const dialog = wrapper.querySelector('.van-dialog');
expect(
dialog.querySelector('.van-dialog__message').outerHTML
).toMatchSnapshot();
});

View File

@ -1,345 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`click option 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">B</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">B</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-overlay" style="z-index: 2013; animation-duration: 0.2s; position: absolute;" name="van-fade"></div>
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s; display: none; z-index: 2014;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>A</span></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>B</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`close-on-click-outside 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s; display: none;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`destroy one item 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<!---->
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`didn\`t find matched option 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis"></div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis"></div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`direction up 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--up" style="bottom: 0px; display: none;">
<!---->
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--up" style="bottom: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`direction up 2`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--up" style="bottom: 1000px;">
<div class="van-popup van-popup--bottom van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-bottom">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--up" style="bottom: 1000px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`disable close-on-click-outside 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`disable dropdown item 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button" tabindex="-1" class="van-dropdown-menu__item van-dropdown-menu__item--disabled"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`render option icon 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"><i class="van-icon van-icon-success van-cell__left-icon">
<!----></i>
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option"><i class="van-icon van-icon-success van-cell__left-icon">
<!----></i>
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`show dropdown item 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`show dropdown item 2`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active van-dropdown-menu__title--down"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0s; display: none;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`show dropdown item 3`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">A</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0s; display: none;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px;">
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s; display: none;" name="van-popup-slide-top">
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active">
<div class="van-cell__title"><span>A</span></div>
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon">
<!----></i></div>
</div>
<div role="button" tabindex="0" class="van-cell van-cell--clickable van-dropdown-item__option">
<div class="van-cell__title"><span>B</span></div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`title prop 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">Title</div></span></div>
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">Title</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;
exports[`title slot 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button" tabindex="0" class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"><div class="van-ellipsis">
Custom Title
</div></span></div>
</div>
<div>
<div class="van-dropdown-item van-dropdown-item--down" style="top: 0px; display: none;">
<!---->
</div>
</div>
</div>
`;

View File

@ -0,0 +1,850 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`click option 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2007; position: absolute; animation-duration: 0.2s; display: none;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2007; transition-duration: 0.2s; display: none;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`close-on-click-outside 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2004; position: absolute; animation-duration: 0.2s; display: none;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2004; transition-duration: 0.2s; display: none;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`destroy one item 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`direction up 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="bottom: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--up"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
<div style="bottom: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--up"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`direction up 2`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--active">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="bottom: 768px;"
class="van-dropdown-item van-dropdown-item--up"
>
<transition-stub>
<div style="z-index: 2006; position: absolute; animation-duration: 0.2s;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2006; transition-duration: 0.2s;"
class="van-popup van-popup--bottom van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="bottom: 768px; display: none;"
class="van-dropdown-item van-dropdown-item--up"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`disable close-on-click-outside 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down van-dropdown-menu__title--active">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2005; position: absolute; animation-duration: 0.2s;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2005; transition-duration: 0.2s;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`disable dropdown item 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button"
tabindex="-1"
class="van-dropdown-menu__item van-dropdown-menu__item--disabled"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`render option icon 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down van-dropdown-menu__title--active">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2003; position: absolute; animation-duration: 0.2s;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2003; transition-duration: 0.2s;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<i class="van-badge__wrapper van-icon van-icon-success van-cell__left-icon">
</i>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<i class="van-badge__wrapper van-icon van-icon-success van-cell__left-icon">
</i>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`show dropdown item 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down van-dropdown-menu__title--active">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2001; position: absolute; animation-duration: 0.2s;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2001; transition-duration: 0.2s;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`show dropdown item 2`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title van-dropdown-menu__title--down van-dropdown-menu__title--active">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2001; position: absolute; animation-duration: 0s; display: none;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2001; transition-duration: 0s; display: none;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2002; position: absolute; animation-duration: 0.2s;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2002; transition-duration: 0.2s;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
</div>
`;
exports[`show dropdown item 3`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar van-dropdown-menu__bar--opened">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
A
</div>
</span>
</div>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2001; position: absolute; animation-duration: 0s; display: none;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2001; transition-duration: 0s; display: none;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
<div style="top: 0px;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
<div style="z-index: 2002; position: absolute; animation-duration: 0.2s; display: none;"
class="van-overlay"
>
</div>
</transition-stub>
<transition-stub>
<div style="z-index: 2002; transition-duration: 0.2s; display: none;"
class="van-popup van-popup--top van-dropdown-item__content"
>
<div class="van-cell van-cell--clickable van-dropdown-item__option van-dropdown-item__option--active"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
A
</span>
</div>
<div class="van-cell__value">
<i class="van-badge__wrapper van-icon van-icon-success van-dropdown-item__icon">
</i>
</div>
</div>
<div class="van-cell van-cell--clickable van-dropdown-item__option"
role="button"
tabindex="0"
>
<div class="van-cell__title">
<span>
B
</span>
</div>
<div class="van-cell__value">
</div>
</div>
</div>
</transition-stub>
</div>
</div>
`;
exports[`title prop 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
Title
</div>
</span>
</div>
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
Title
</div>
</span>
</div>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;
exports[`title slot 1`] = `
<div class="van-dropdown-menu">
<div class="van-dropdown-menu__bar">
<div role="button"
tabindex="0"
class="van-dropdown-menu__item"
>
<span class="van-dropdown-menu__title">
<div class="van-ellipsis">
Custom Title
</div>
</span>
</div>
</div>
<div style="top: 0px; display: none;"
class="van-dropdown-item van-dropdown-item--down"
>
<transition-stub>
</transition-stub>
<transition-stub>
</transition-stub>
</div>
</div>
`;

View File

@ -1,255 +0,0 @@
import { mount, later } from '../../../test';
function renderWrapper(options = {}) {
return mount({
template: `
<van-dropdown-menu :direction="direction" :close-on-click-outside="closeOnClickOutside">
<van-dropdown-item v-model="value" :title="title" :options="options" />
<van-dropdown-item v-model="value" :title="title" :options="options" />
</van-dropdown-menu>
`,
data() {
return {
value: options.value || 0,
title: options.title || '',
direction: options.direction || 'down',
closeOnClickOutside: options.closeOnClickOutside,
options: [
{ text: 'A', value: 0, icon: options.icon },
{ text: 'B', value: 1, icon: options.icon },
],
};
},
});
}
test('show dropdown item', async () => {
const wrapper = renderWrapper();
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
titles[1].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
titles[1].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('render option icon', async () => {
const wrapper = renderWrapper({
icon: 'success',
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('close-on-click-outside', async () => {
const wrapper = renderWrapper({
closeOnClickOutside: true,
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
document.body.click();
expect(wrapper.html()).toMatchSnapshot();
});
test('disable close-on-click-outside', async () => {
const wrapper = renderWrapper({
closeOnClickOutside: false,
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
document.body.click();
expect(wrapper.html()).toMatchSnapshot();
});
test('direction up', async () => {
const { innerHeight } = window;
window.innerHeight = 1000;
const wrapper = renderWrapper({
direction: 'up',
});
await later();
expect(wrapper.html()).toMatchSnapshot();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
window.innerHeight = innerHeight;
});
test('click option', async () => {
const wrapper = renderWrapper();
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
const options = wrapper.findAll('.van-dropdown-item .van-cell');
options[1].trigger('click');
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('title prop', async () => {
const wrapper = renderWrapper({ title: 'Title' });
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('didn`t find matched option', async () => {
const wrapper = renderWrapper({ value: -1 });
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('destroy one item', async () => {
const wrapper = mount({
template: `
<van-dropdown-menu>
<van-dropdown-item v-if="render" v-model="value" :options="options" />
<van-dropdown-item v-model="value" :options="options" />
</van-dropdown-menu>
`,
data() {
return {
value: 0,
render: true,
options: [
{ text: 'A', value: 0 },
{ text: 'B', value: 1 },
],
};
},
});
await later();
wrapper.setData({ render: false });
expect(wrapper.html()).toMatchSnapshot();
});
test('disable dropdown item', async () => {
const wrapper = mount({
template: `
<van-dropdown-menu>
<van-dropdown-item disabled v-model="value" :options="options" />
</van-dropdown-menu>
`,
data() {
return {
value: 0,
options: [
{ text: 'A', value: 0 },
{ text: 'B', value: 1 },
],
};
},
});
const title = wrapper.find('.van-dropdown-menu__title');
title.trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('change event', async () => {
const onChange = jest.fn();
const wrapper = mount({
template: `
<van-dropdown-menu>
<van-dropdown-item v-model="value" :options="options" @change="onChange" />
<van-dropdown-item v-model="value" :options="options" />
</van-dropdown-menu>
`,
data() {
return {
value: 0,
options: [
{ text: 'A', value: 0 },
{ text: 'B', value: 1 },
],
};
},
methods: {
onChange,
},
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
titles[0].trigger('click');
const options = wrapper.findAll('.van-dropdown-item .van-cell');
options[0].trigger('click');
expect(onChange).toHaveBeenCalledTimes(0);
options[1].trigger('click');
expect(onChange).toHaveBeenCalledWith(1);
expect(onChange).toHaveBeenCalledTimes(1);
});
test('toggle method', async (done) => {
const wrapper = mount({
template: `
<van-dropdown-menu>
<van-dropdown-item ref="item" />
</van-dropdown-menu>
`,
async mounted() {
// show
this.$refs.item.toggle(true, { immediate: true });
await later();
const content = wrapper.find('.van-dropdown-item__content');
expect(content.style.display).toEqual('');
// hide
this.$refs.item.toggle(false, { immediate: true });
await later();
expect(content.style.display).toEqual('none');
done();
},
});
});
test('title slot', () => {
const wrapper = mount({
template: `
<van-dropdown-menu>
<van-dropdown-item>
<template #title>
Custom Title
</template>
</van-dropdown-item>
</van-dropdown-menu>
`,
});
expect(wrapper.html()).toMatchSnapshot();
});

View File

@ -0,0 +1,280 @@
import { later, mount } from '../../../test';
import { reactive, ref, onMounted } from 'vue';
import DropdownItem from '../../dropdown-item';
import DropdownMenu, { DropdownMenuDirection } from '..';
function renderWrapper(
options: {
value?: number;
title?: string;
direction?: DropdownMenuDirection | undefined;
closeOnClickOutside?: boolean;
icon?: string;
} = {}
) {
return mount({
setup() {
const state = reactive({
value: options.value || 0,
title: options.title || '',
direction: options.direction || 'down',
closeOnClickOutside: !!options.closeOnClickOutside,
options: [
{ text: 'A', value: 0, icon: options.icon },
{ text: 'B', value: 1, icon: options.icon },
],
});
return () => (
<DropdownMenu
direction={state.direction}
closeOnClickOutside={state.closeOnClickOutside}
>
<DropdownItem
modelValue={state.value}
title={state.title}
options={state.options}
/>
<DropdownItem
modelValue={state.value}
title={state.title}
options={state.options}
/>
</DropdownMenu>
);
},
});
}
test('show dropdown item', async () => {
const wrapper = renderWrapper();
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
await titles[1].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
await titles[1].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('render option icon', async () => {
const wrapper = renderWrapper({
icon: 'success',
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('close-on-click-outside', async () => {
const wrapper = renderWrapper({
closeOnClickOutside: true,
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
document.body.click();
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('disable close-on-click-outside', async () => {
const wrapper = renderWrapper({
closeOnClickOutside: false,
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
document.body.click();
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('direction up', async () => {
const wrapper = renderWrapper({
direction: 'up',
});
await later();
expect(wrapper.html()).toMatchSnapshot();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('click option', async () => {
const wrapper = renderWrapper();
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
const options = wrapper.findAll('.van-dropdown-item .van-cell');
await options[1].trigger('click');
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('title prop', async () => {
const wrapper = renderWrapper({ title: 'Title' });
await later();
expect(wrapper.html()).toMatchSnapshot();
});
test('destroy one item', async () => {
const wrapper = mount({
props: {
render: {
type: Boolean,
default: true,
},
},
setup(props) {
const options = [
{ text: 'A', value: 0 },
{ text: 'B', value: 1 },
];
const value = 0;
return () => (
<DropdownMenu>
{props.render && (
<DropdownItem modelValue={value} options={options} />
)}
<DropdownItem modelValue={value} options={options} />
</DropdownMenu>
);
},
});
await later();
await wrapper.setProps({ render: false });
expect(wrapper.html()).toMatchSnapshot();
});
test('disable dropdown item', async () => {
const wrapper = mount({
setup() {
const options = [
{ text: 'A', value: 0 },
{ text: 'B', value: 1 },
];
return () => (
<DropdownMenu>
<DropdownItem disabled modelValue={0} options={options} />
</DropdownMenu>
);
},
});
await later();
const title = wrapper.find('.van-dropdown-menu__title');
await title.trigger('click');
expect(wrapper.html()).toMatchSnapshot();
});
test('change event', async () => {
const onChange = jest.fn();
const wrapper = mount({
setup() {
const options = [
{ text: 'A', value: 0 },
{ text: 'B', value: 1 },
];
return () => (
<DropdownMenu>
<DropdownItem modelValue={0} options={options} onChange={onChange} />
<DropdownItem modelValue={0} options={options} />
</DropdownMenu>
);
},
});
await later();
const titles = wrapper.findAll('.van-dropdown-menu__title');
await titles[0].trigger('click');
const options = wrapper.findAll('.van-dropdown-item .van-cell');
await options[0].trigger('click');
expect(onChange).toHaveBeenCalledTimes(0);
await options[1].trigger('click');
expect(onChange).toHaveBeenCalledWith(1);
expect(onChange).toHaveBeenCalledTimes(1);
});
test('toggle method', async (done) => {
const wrapper = mount({
setup() {
const item = ref();
onMounted(async () => {
// show
item.value.toggle(true, { immediate: true });
await later();
expect(
wrapper.find('.van-dropdown-item__content').style.display
).toEqual('');
// hide
item.value.toggle(false, { immediate: true });
await later();
expect(
wrapper.find('.van-dropdown-item__content').style.display
).toEqual('none');
done();
});
return () => (
<DropdownMenu>
<DropdownItem ref={item} />
</DropdownMenu>
);
},
});
});
test('title slot', async () => {
const wrapper = mount({
setup() {
return () => (
<DropdownMenu>
<DropdownItem>{{ title: () => 'Custom Title' }}</DropdownItem>
</DropdownMenu>
);
},
});
await later();
expect(wrapper.html()).toMatchSnapshot();
});

View File

@ -97,6 +97,10 @@ export default defineComponent({
type: Boolean,
default: null,
},
clearIcon: {
type: String,
default: 'clear',
},
modelValue: {
type: [String, Number],
default: '',
@ -546,7 +550,11 @@ export default defineComponent({
<div class={bem('body')}>
{renderInput()}
{showClear.value && (
<Icon name="clear" class={bem('clear')} onTouchstart={onClear} />
<Icon
name={props.clearIcon}
class={bem('clear')}
onTouchstart={onClear}
/>
)}
{renderRightIcon()}
{slots.button && <div class={bem('button')}>{slots.button()}</div>}

View File

@ -247,21 +247,22 @@ Use `input-align` prop to align the input value.
| required | Whether to show required mark | _boolean_ | `false` |
| center | Whether to center content vertically | _boolean_ | `true` |
| clearable | Whether to be clearable | _boolean_ | `false` |
| clear-icon `v3.0.12` | Clear icon name | _string_ | `clear` |
| clear-trigger | When to display the clear icon, `always` means to display the icon when value is not empty, `focus` means to display the icon when input is focused | _string_ | `focus` |
| clickable | Whether to show click feedback when clicked | _boolean_ | `false` |
| is-link | Whether to show link icon | _boolean_ | `false` |
| autofocus | Whether to auto focus, unsupported in iOS | _boolean_ | `false` |
| show-word-limit | Whether to show word limit, need to set the `maxlength` prop | _boolean_ | `false` |
| error | Whether to show error info | _boolean_ | `false` |
| error | Whether to mark the input content in red | _boolean_ | `false` |
| error-message | Error message | _string_ | - |
| formatter | Input value formatter | _Function_ | - |
| error-message-align | Error message align, can be set to `center` `right` | _string_ | `left` |
| formatter | Input value formatter | _(val: string) => string_ | - |
| format-trigger | When to format valuecan be set to `onBlur` | _string_ | `onChange` |
| arrow-direction | Can be set to `left` `up` `down` | _string_ | `right` |
| label-class | Label className | _string \| Array \| object_ | - |
| label-width | Label width | _number \| string_ | `6.2em` |
| label-align | Label align, can be set to `center` `right` | _string_ | `left` |
| input-align | Input align, can be set to `center` `right` | _string_ | `left` |
| error-message-align | Error message align, can be set to `center` `right` | _string_ | `left` |
| autosize | Textarea auto resizecan accpet an object,<br>e.g. { maxHeight: 100, minHeight: 50 } | _boolean \| object_ | `false` |
| left-icon | Left side icon name | _string_ | - |
| right-icon | Right side icon name | _string_ | - |

View File

@ -270,21 +270,22 @@ export default {
| required | 是否显示表单必填星号 | _boolean_ | `false` |
| center | 是否使内容垂直居中 | _boolean_ | `false` |
| clearable | 是否启用清除图标,点击清除图标后会清空输入框 | _boolean_ | `false` |
| clear-icon `v3.0.12` | 清除[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `clear` |
| clear-trigger | 显示清除图标的时机,`always` 表示输入框不为空时展示,<br>`focus` 表示输入框聚焦且不为空时展示 | _string_ | `focus` |
| clickable | 是否开启点击反馈 | _boolean_ | `false` |
| is-link | 是否展示右侧箭头并开启点击反馈 | _boolean_ | `false` |
| autofocus | 是否自动聚焦iOS 系统不支持该属性 | _boolean_ | `false` |
| show-word-limit | 是否显示字数统计,需要设置`maxlength`属性 | _boolean_ | `false` |
| show-word-limit | 是否显示字数统计,需要设置 `maxlength` 属性 | _boolean_ | `false` |
| error | 是否将输入内容标红 | _boolean_ | `false` |
| error-message | 底部错误提示文案,为空时不展示 | _string_ | - |
| formatter | 输入内容格式化函数 | _Function_ | - |
| error-message-align | 错误提示文案对齐方式,可选值为 `center` `right` | _string_ | `left` |
| formatter | 输入内容格式化函数 | _(val: string) => string_ | - |
| format-trigger | 格式化函数触发的时机,可选值为 `onBlur` | _string_ | `onChange` |
| arrow-direction | 箭头方向,可选值为 `left` `up` `down` | _string_ | `right` |
| label-class | 左侧文本额外类名 | _string \| Array \| object_ | - |
| label-width | 左侧文本宽度,默认单位为 `px` | _number \| string_ | `6.2em` |
| label-align | 左侧文本对齐方式,可选值为 `center` `right` | _string_ | `left` |
| input-align | 输入框对齐方式,可选值为 `center` `right` | _string_ | `left` |
| error-message-align | 错误提示文案对齐方式,可选值为 `center` `right` | _string_ | `left` |
| autosize | 是否自适应内容高度,只对 textarea 有效,<br>可传入对象,如 { maxHeight: 100, minHeight: 50 }<br>单位为`px` | _boolean \| object_ | `false` |
| left-icon | 左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - |
| right-icon | 右侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - |

View File

@ -1,5 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should change clear icon when using clear-icon prop 1`] = `
<i class="van-badge__wrapper van-icon van-icon-cross van-field__clear">
</i>
`;
exports[`should render colon when using colon prop 1`] = `
<div class="van-cell__title van-field__label">
<span>

View File

@ -430,3 +430,17 @@ test('should allow to set autocomplete attribute', () => {
'on'
);
});
test('should change clear icon when using clear-icon prop', async () => {
const wrapper = mount(Field, {
props: {
clearable: true,
clearIcon: 'cross',
modelValue: 'test',
},
});
const input = wrapper.find('input');
await input.trigger('focus');
expect(wrapper.find('.van-field__clear').html()).toMatchSnapshot();
});

View File

@ -103,5 +103,4 @@ ImagePreview.install = (app: App) => {
app.use(withInstall<typeof VanImagePreview>(VanImagePreview));
};
export default ImagePreview;
export { ImagePreview };

View File

@ -0,0 +1,5 @@
import { ImagePreview, ImagePreviewOptions } from './function-call';
export default ImagePreview;
export { ImagePreview };
export type { ImagePreviewOptions };

View File

@ -76,113 +76,83 @@ exports[`should swipe to currect index after calling the swipeTo method 1`] = `
`;
exports[`zoom in and drag image to move 1`] = `
DOMWrapper {
"element": <div
class="van-image van-image-preview__image"
style="transition-duration: .3s;"
<div class="van-image van-image-preview__image"
style="transition-duration: .3s;"
>
<img src="https://img.yzcdn.cn/1.png"
class="van-image__img"
style="object-fit: contain;"
>
<img
class="van-image__img"
src="https://img.yzcdn.cn/1.png"
style="object-fit: contain;"
/>
<div
class="van-image__loading"
>
<div
class="van-loading van-loading--spinner"
>
<span
class="van-loading__spinner van-loading__spinner--spinner"
>
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
</span>
<!---->
</div>
<div class="van-image__loading">
<div class="van-loading van-loading--spinner">
<span class="van-loading__spinner van-loading__spinner--spinner">
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
</span>
</div>
<!---->
</div>,
"style": CSSStyleDeclaration {
"0": "transition-duration",
"_importants": Object {
"transition-duration": undefined,
},
"_length": 1,
"_onChange": [Function],
"_values": Object {
"transition-duration": ".3s",
},
},
}
</div>
</div>
`;
exports[`zoom in and drag image to move 2`] = `
DOMWrapper {
"element": <div
class="van-image van-image-preview__image"
style="transition-duration: .3s;"
<div class="van-image van-image-preview__image"
style="transition-duration: .3s;"
>
<img src="https://img.yzcdn.cn/1.png"
class="van-image__img"
style="object-fit: contain;"
>
<img
class="van-image__img"
src="https://img.yzcdn.cn/1.png"
style="object-fit: contain;"
/>
<div
class="van-image__loading"
>
<div
class="van-loading van-loading--spinner"
>
<span
class="van-loading__spinner van-loading__spinner--spinner"
>
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
<i />
</span>
<!---->
</div>
<div class="van-image__loading">
<div class="van-loading van-loading--spinner">
<span class="van-loading__spinner van-loading__spinner--spinner">
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
<i>
</i>
</span>
</div>
<!---->
</div>,
"style": CSSStyleDeclaration {
"0": "transition-duration",
"_importants": Object {
"transition-duration": undefined,
},
"_length": 1,
"_onChange": [Function],
"_values": Object {
"transition-duration": ".3s",
},
},
}
</div>
</div>
`;

View File

@ -1,5 +1,5 @@
import { createApp } from 'vue';
import { ImagePreview } from '..';
import { ImagePreview } from '../function-call';
import ImagePreviewComponent from '../ImagePreview';
test('should expose ImagePreviewComponent in ImagePreview.Component', () => {

View File

@ -7,7 +7,7 @@ import {
triggerDrag,
mockGetBoundingClientRect,
} from '../../../test';
import { ImagePreview } from '..';
import { ImagePreview } from '../function-call';
import ImagePreviewComponent from '../ImagePreview';
const images = [
@ -328,12 +328,12 @@ test('zoom in and drag image to move', async () => {
// drag image before load
triggerDrag(image, 300, 300);
expect(wrapper.find('.van-image')).toMatchSnapshot();
expect(wrapper.find('.van-image').html()).toMatchSnapshot();
// drag image after load
image.trigger('load');
triggerDrag(image, 300, 300);
expect(wrapper.find('.van-image')).toMatchSnapshot();
expect(wrapper.find('.van-image').html()).toMatchSnapshot();
restore();
});

View File

@ -103,5 +103,4 @@ Notify.install = (app: App) => {
Notify.Component = withInstall<typeof VanNotify>(VanNotify);
export default Notify;
export { Notify };

6
src/notify/index.ts Normal file
View File

@ -0,0 +1,6 @@
import { Notify, NotifyOptions } from './function-call';
import type { NotifyType } from './Notify';
export default Notify;
export { Notify };
export type { NotifyType, NotifyOptions };

View File

@ -1,7 +1,7 @@
import { createApp } from 'vue';
import { later } from '../../../test';
import { trigger } from '../../utils';
import { Notify } from '..';
import { Notify } from '../function-call';
import NotifyComponent from '../Notify';
test('should not throw error if calling clear method before render notify', () => {

View File

@ -120,13 +120,17 @@ Use `action` slot to custom right button, `cancel` event will no longer be Emitt
| maxlength | Max length of value | _number \| string_ | - |
| placeholder | Placeholder | _string_ | - |
| clearable | Whether to be clearable | _boolean_ | `true` |
| clear-icon `v3.0.12` | Clear icon name | _string_ | `clear` |
| clear-trigger | When to display the clear icon, `always` means to display the icon when value is not empty, `focus` means to display the icon when input is focused | _string_ | `focus` |
| autofocus | Whether to auto focus, unsupported in iOS | _boolean_ | `false` |
| show-action | Whether to show right action button | _boolean_ | `false` |
| action-text | Text of action button | _boolean_ | `Cancel` |
| disabled | Whether to disable field | _boolean_ | `false` |
| readonly | Whether to be readonly | _boolean_ | `false` |
| error | Whether to show error info | _boolean_ | `false` |
| error | Whether to mark the input content in red | _boolean_ | `false` |
| error-message `v3.0.12` | Error message | _string_ | - |
| formatter `v3.0.12` | Input value formatter | _(val: string) => string_ | - |
| format-trigger `v3.0.12` | When to format valuecan be set to `onBlur` | _string_ | `onChange` |
| input-align | Text align of field, can be set to `center` `right` | _string_ | `left` |
| left-icon | Left icon name | _string_ | `search` |
| right-icon | Right icon name | _string_ | - |

View File

@ -136,6 +136,7 @@ export default {
| maxlength | 输入的最大字符数 | _number \| string_ | - |
| placeholder | 占位提示文字 | _string_ | - |
| clearable | 是否启用清除图标,点击清除图标后会清空输入框 | _boolean_ | `true` |
| clear-icon `v3.0.12` | 清除[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `clear` |
| clear-trigger | 显示清除图标的时机,`always` 表示输入框不为空时展示,<br>`focus` 表示输入框聚焦且不为空时展示 | _string_ | `focus` |
| autofocus | 是否自动聚焦iOS 系统不支持该属性 | _boolean_ | `false` |
| show-action | 是否在搜索框右侧显示取消按钮 | _boolean_ | `false` |
@ -143,6 +144,9 @@ export default {
| disabled | 是否禁用输入框 | _boolean_ | `false` |
| readonly | 是否将输入框设为只读状态,只读状态下无法输入内容 | _boolean_ | `false` |
| error | 是否将输入内容标红 | _boolean_ | `false` |
| error-message | 底部错误提示文案,为空时不展示 | _string_ | - |
| formatter `v3.0.12` | 输入内容格式化函数 | _(val: string) => string_ | - |
| format-trigger `v3.0.12` | 格式化函数触发的时机,可选值为 `onBlur` | _string_ | `onChange` |
| input-align | 输入框内容对齐方式,可选值为 `center` `right` | _string_ | `left` |
| left-icon | 输入框左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `search` |
| right-icon | 输入框右侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - |

View File

@ -15,7 +15,7 @@ import { useExpose } from '../composables/use-expose';
import { Field } from '../field';
// Types
import type { FieldClearTrigger } from '../field/types';
import type { FieldClearTrigger, FieldFormatTrigger } from '../field/types';
const [name, bem, t] = createNamespace('search');
@ -28,12 +28,16 @@ export default defineComponent({
props: {
label: String,
clearIcon: String,
rightIcon: String,
formatter: Function as PropType<(value: string) => string>,
modelValue: String,
actionText: String,
background: String,
showAction: Boolean,
errorMessage: String,
clearTrigger: String as PropType<FieldClearTrigger>,
formatTrigger: String as PropType<FieldFormatTrigger>,
shape: {
type: String as PropType<SearchShape>,
default: 'square',
@ -48,7 +52,7 @@ export default defineComponent({
},
},
emits: ['update:modelValue', 'search', 'cancel'],
emits: ['search', 'cancel', 'update:modelValue'],
setup(props, { emit, slots, attrs }) {
const filedRef = ref<ComponentInstance>();
@ -99,10 +103,14 @@ export default defineComponent({
const fieldPropNames = [
'leftIcon',
'clearIcon',
'rightIcon',
'formatter',
'clearable',
'modelValue',
'clearTrigger',
'errorMessage',
'formatTrigger',
] as const;
const renderField = () => {

View File

@ -1,28 +1,39 @@
import { nextTick, ref } from 'vue';
import { VueWrapper } from '@vue/test-utils';
import { mockScrollTop, mount } from '../../../test';
import { Sticky } from '..';
import { ComponentInstance } from '../../utils';
Object.defineProperty(window.HTMLElement.prototype, 'clientHeight', {
value: 640,
});
function mockStickyRect(
wrapper: VueWrapper<ComponentInstance>,
rect: Partial<DOMRect>
) {
const mocked = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue(rect as DOMRect);
return () => mocked.mockRestore();
}
test('should sticky to top after scrolling', async () => {
const wrapper = mount({
render() {
return <Sticky style="height: 10px;">Content</Sticky>;
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
});
const restore = mockStickyRect(wrapper, {
top: -100,
bottom: -90,
});
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
restore();
});
test('should sticky to bottom after scrolling', async () => {
@ -35,17 +46,15 @@ test('should sticky to bottom after scrolling', async () => {
);
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: 640,
bottom: 650,
});
const restore = mockStickyRect(wrapper, {
top: 640,
bottom: 650,
});
await mockScrollTop(0);
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
restore();
});
test('should update z-index when using z-index prop', async () => {
@ -59,17 +68,15 @@ test('should update z-index when using z-index prop', async () => {
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
});
const restore = mockStickyRect(wrapper, {
top: -100,
bottom: -90,
});
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
restore();
});
test('should add offset top when using offset-top prop', async () => {
@ -83,23 +90,21 @@ test('should add offset top when using offset-top prop', async () => {
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
});
const restore = mockStickyRect(wrapper, {
top: -100,
bottom: -90,
});
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
restore();
});
test('should allow to using offset-top prop with rem unit', async () => {
const originGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = () => ({ fontSize: '16px' });
window.getComputedStyle = () => ({ fontSize: '16px' } as CSSStyleDeclaration);
const wrapper = mount({
render() {
@ -111,22 +116,20 @@ test('should allow to using offset-top prop with rem unit', async () => {
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
});
const restore = mockStickyRect(wrapper, {
top: -100,
bottom: -90,
});
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
restore();
window.getComputedStyle = originGetComputedStyle;
});
test('should allow to using offset-top prop with vw unit', async () => {
window.innerWidth = 300;
Object.defineProperty(window, 'innerWidth', { value: 300 });
const wrapper = mount({
render() {
@ -138,17 +141,15 @@ test('should allow to using offset-top prop with vw unit', async () => {
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
});
const restore = mockStickyRect(wrapper, {
top: -100,
bottom: -90,
});
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
restore();
});
test('should not trigger scroll event when hidden', () => {
@ -187,19 +188,19 @@ test('should sticky inside container when using container prop', async () => {
});
const mockStickyRect = jest
.spyOn(wrapper.element.firstElementChild, 'getBoundingClientRect')
.spyOn(wrapper.element.firstElementChild!, 'getBoundingClientRect')
.mockReturnValue({
height: 44,
width: 88,
top: -100,
bottom: -56,
});
} as DOMRect);
const mockContainerRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: 50,
});
} as DOMRect);
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
@ -209,11 +210,11 @@ test('should sticky inside container when using container prop', async () => {
width: 88,
top: -120,
bottom: -76,
});
} as DOMRect);
mockContainerRect.mockReturnValue({
top: -120,
bottom: 30,
});
} as DOMRect);
await mockScrollTop(120);
expect(wrapper.html()).toMatchSnapshot();
mockContainerRect.mockRestore();
@ -252,13 +253,13 @@ test('should sticky inside container bottom when using container prop', async ()
width: 88,
top: 690,
bottom: 734,
});
} as DOMRect);
const mockContainerRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: 540,
bottom: 734,
});
} as DOMRect);
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
@ -268,11 +269,11 @@ test('should sticky inside container bottom when using container prop', async ()
width: 88,
top: 770,
bottom: 814,
});
} as DOMRect);
mockContainerRect.mockReturnValue({
top: 620,
bottom: 814,
});
} as DOMRect);
await mockScrollTop(20);
expect(wrapper.html()).toMatchSnapshot();
mockContainerRect.mockRestore();
@ -286,10 +287,13 @@ test('should emit scroll event when visibility changed', async () => {
const unobserve = jest.fn();
const onScroll = jest.fn();
let observerCallback;
type ObserverCallback = (
entries: Partial<IntersectionObserverEntry>[]
) => void;
let observerCallback: ObserverCallback = () => {};
window.IntersectionObserver = class IntersectionObserver {
constructor(callback) {
window.IntersectionObserver = class MockIntersectionObserver {
constructor(callback: ObserverCallback) {
observerCallback = callback;
}
@ -300,7 +304,7 @@ test('should emit scroll event when visibility changed', async () => {
unobserve() {
unobserve();
}
};
} as any;
const wrapper = mount({
render() {
@ -337,15 +341,14 @@ test('should emit change event when sticky status changed', async () => {
style: 'height: 10px',
},
});
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
});
const restore = mockStickyRect(wrapper as any, {
top: -100,
bottom: -90,
});
await mockScrollTop(100);
expect(wrapper.emitted('change')[0]).toEqual([true]);
expect(wrapper.emitted('change')![0]).toEqual([true]);
mockStickyRect.mockRestore();
restore();
});

View File

@ -139,14 +139,14 @@ export default defineComponent({
});
const trackStyle = computed(() => {
const mainAxis = props.vertical ? 'height' : 'width';
const crossAxis = props.vertical ? 'width' : 'height';
const style: CSSProperties = {
transitionDuration: `${state.swiping ? 0 : props.duration}ms`,
transform: `translate${props.vertical ? 'Y' : 'X'}(${state.offset}px)`,
};
if (size.value) {
const mainAxis = props.vertical ? 'height' : 'width';
const crossAxis = props.vertical ? 'width' : 'height';
style[mainAxis] = `${trackSize.value}px`;
style[crossAxis] = props[crossAxis] ? `${props[crossAxis]}px` : '';
}
@ -225,8 +225,7 @@ export default defineComponent({
if (state.active <= -1) {
move({ pace: count.value });
}
if (state.active >= count.value) {
} else if (state.active >= count.value) {
move({ pace: -count.value });
}
};

View File

@ -1,3 +1,4 @@
import { defineComponent } from 'vue';
import { mount, later } from '../../../test';
import { Tab } from '..';
import { Tabs } from '../../tabs';
@ -64,11 +65,11 @@ test('should render correctly after inserting a tab with name', async () => {
});
test('should render Tab inside a component correctly', async () => {
const MyTab = {
const MyTab = defineComponent({
render() {
return <Tab title="2">2</Tab>;
},
};
});
const wrapper = mount({
render() {

View File

@ -185,6 +185,4 @@ Toast.install = (app: App) => {
app.config.globalProperties.$toast = Toast;
};
export default Toast;
export { Toast };
export type { ToastType, ToastPosition };

6
src/toast/index.ts Normal file
View File

@ -0,0 +1,6 @@
import { Toast, ToastOptions } from './function-call';
import type { ToastType, ToastPosition } from './Toast';
export default Toast;
export { Toast };
export type { ToastType, ToastOptions, ToastPosition };

View File

@ -1,7 +1,7 @@
import { later } from '../../../test';
import Toast from '../index';
import ToastComponent from '../Toast';
import { createApp } from 'vue';
import { later } from '../../../test';
import { Toast } from '../function-call';
import ToastComponent from '../Toast';
test('toast disappeared after duration', async () => {
const onClose = jest.fn();

View File

@ -1,41 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`content slot 1`] = `
<div class="van-tree-select" style="height: 300px;">
<div class="van-sidebar van-tree-select__nav"><a class="van-sidebar-item van-sidebar-item--select van-tree-select__nav-item">
<div class="van-sidebar-item__text">group1
<!---->
</div>
</a></div>
<div class="van-tree-select__content">Custom Content</div>
</div>
`;
exports[`empty list 1`] = `
<div class="van-tree-select" style="height: 300px;">
<div class="van-sidebar van-tree-select__nav"></div>
<div class="van-tree-select__content"></div>
</div>
`;
exports[`height prop 1`] = `
<div class="van-tree-select" style="height: 100vh;">
<div class="van-sidebar van-tree-select__nav"></div>
<div class="van-tree-select__content"></div>
</div>
`;
exports[`nav render badge 1`] = `
<div class="van-tree-select" style="height: 300px;">
<div class="van-sidebar van-tree-select__nav"><a class="van-sidebar-item van-sidebar-item--select van-tree-select__nav-item">
<div class="van-sidebar-item__text">group1<div class="van-badge van-sidebar-item__badge">3</div>
</div>
</a></div>
<div class="van-tree-select__content"></div>
</div>
`;
exports[`selected-icon prop 1`] = `
<div class="van-ellipsis van-tree-select__item van-tree-select__item--active">city1<i class="van-icon van-icon-foo van-tree-select__selected">
<!----></i></div>
`;

View File

@ -0,0 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should change selected icon when using selected-icon prop 1`] = `
<div class="van-ellipsis van-tree-select__item van-tree-select__item--active">
city1
<i class="van-badge__wrapper van-icon van-icon-foo van-tree-select__selected">
</i>
</div>
`;
exports[`should render content slot correctly 1`] = `
<div class="van-tree-select"
style="height: 300px;"
>
<div class="van-sidebar van-tree-select__nav">
<a class="van-sidebar-item van-sidebar-item--select van-tree-select__nav-item">
<div class="van-badge__wrapper van-sidebar-item__text">
group1
</div>
</a>
</div>
<div class="van-tree-select__content">
Custom Content
</div>
</div>
`;
exports[`should render empty TreeSelect correctly 1`] = `
<div class="van-tree-select"
style="height: 300px;"
>
<div class="van-sidebar van-tree-select__nav">
</div>
<div class="van-tree-select__content">
</div>
</div>
`;
exports[`should render nav badge correctly 1`] = `
<div class="van-tree-select"
style="height: 300px;"
>
<div class="van-sidebar van-tree-select__nav">
<a class="van-sidebar-item van-sidebar-item--select van-tree-select__nav-item">
<div class="van-badge__wrapper van-sidebar-item__text">
group1
<div class="van-badge van-badge--fixed">
3
</div>
</div>
</a>
</div>
<div class="van-tree-select__content">
</div>
</div>
`;

View File

@ -1,339 +0,0 @@
import { TreeSelect } from '..';
import { mount } from '../../../test';
test('empty list', () => {
expect(mount(TreeSelect)).toMatchSnapshot();
});
const mockItem = {
text: 'city1',
id: 1,
};
const mockItem2 = {
text: 'city2',
id: 2,
};
const mockItems = [
{
text: 'group1',
children: [mockItem],
},
{
text: 'group2',
children: [mockItem],
},
];
test('click-nav event', () => {
const onClickNav = jest.fn();
const wrapper = mount(TreeSelect, {
props: {
items: mockItems,
},
context: {
on: {
'click-nav': onClickNav,
},
},
});
const navItems = wrapper.findAll('.van-tree-select__nav-item');
navItems[1].trigger('click');
expect(onClickNav).toHaveBeenCalledWith(1);
});
test('click-item event', () => {
const onClickItem = jest.fn();
const wrapper = mount(TreeSelect, {
props: {
items: mockItems,
},
context: {
on: {
'click-item': onClickItem,
},
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[0].trigger('click');
expect(onClickItem).toHaveBeenCalledWith(mockItem);
});
test('click disabled nav', () => {
const onClickNav = jest.fn();
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
children: [mockItem],
disabled: true,
},
],
},
context: {
on: {
'click-nav': onClickNav,
},
},
});
const items = wrapper.findAll('.van-tree-select__nav-item');
items[0].trigger('click');
expect(onClickNav).toHaveBeenCalledTimes(0);
});
test('click disabled item', () => {
const onClickItem = jest.fn();
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
children: [
{
...mockItem,
disabled: true,
},
],
},
],
},
context: {
on: {
'click-item': onClickItem,
},
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[0].trigger('click');
expect(onClickItem).toHaveBeenCalledTimes(0);
});
test('content slot', () => {
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
},
],
},
slots: {
content: () => 'Custom Content',
},
});
expect(wrapper.html()).toMatchSnapshot();
});
test('height prop', () => {
const wrapper = mount(TreeSelect, {
props: {
height: '100vh',
},
});
expect(wrapper.html()).toMatchSnapshot();
});
test('nav render badge', () => {
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
badge: 3,
},
],
},
});
expect(wrapper.html()).toMatchSnapshot();
});
test('use sync modifier in main-active-index', () => {
const wrapper = mount({
template: `
<van-tree-select
:items="items"
:main-active-index.sync="mainActiveIndex"
/>
`,
data() {
return {
mainActiveIndex: -1,
items: mockItems,
};
},
});
const navItems = wrapper.findAll('.van-tree-select__nav-item');
navItems[0].trigger('click');
expect(wrapper.vm.mainActiveIndex).toEqual(0);
});
test('use sync modifier in active-id', () => {
const wrapper = mount({
template: `
<van-tree-select
:items="items"
:main-active-index="0"
:active-id.sync="activeId"
/>
`,
data() {
return {
activeId: mockItem.id,
mainActiveIndex: 0,
items: [
{
text: 'group1',
children: [mockItem, mockItem2],
},
],
};
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual(mockItem2.id);
});
test('multiple select', () => {
const wrapper = mount({
template: `
<van-tree-select
:items="items"
:main-active-index="0"
:active-id.sync="activeId"
/>
`,
data() {
return {
activeId: [],
mainActiveIndex: 0,
items: [
{
text: 'group1',
children: [mockItem, mockItem2],
},
],
};
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[0].trigger('click');
items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual([mockItem.id, mockItem2.id]);
items[0].trigger('click');
items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual([]);
});
test('max prop', () => {
const wrapper = mount({
template: `
<van-tree-select
:max="1"
:items="items"
:main-active-index="0"
:active-id.sync="activeId"
/>
`,
data() {
return {
activeId: [],
items: [
{
text: 'group1',
children: [mockItem, mockItem2],
},
],
};
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[0].trigger('click');
items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual([mockItem.id]);
});
test('className of nav', () => {
const wrapper = mount(TreeSelect, {
props: {
mainActiveIndex: 0,
items: [
{
text: 'group1',
className: 'my-class',
children: [],
},
],
},
});
const items = wrapper.findAll('.van-tree-select__nav-item');
expect(items[0].element.classList.contains('my-class')).toBeTruthy();
});
test('should sync value before trigger click-item event', (done) => {
const wrapper = mount({
template: `
<van-tree-select
:items="items"
:main-active-index="0"
:active-id.sync="activeId"
@click-item="onClickItem"
/>
`,
data() {
return {
activeId: mockItem.id,
mainActiveIndex: 0,
items: [
{
text: 'group1',
children: [mockItem, mockItem2],
},
],
};
},
methods: {
onClickItem() {
expect(wrapper.vm.activeId).toEqual(mockItem2.id);
done();
},
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[1].trigger('click');
});
test('selected-icon prop', () => {
const wrapper = mount(TreeSelect, {
props: {
items: mockItems,
activeId: 1,
mainActiveIndex: 0,
selectedIcon: 'foo',
},
});
expect(wrapper.find('.van-tree-select__item')).toMatchSnapshot();
});

View File

@ -0,0 +1,232 @@
import { TreeSelect } from '..';
import { mount } from '../../../test';
const mockItem = {
text: 'city1',
id: 1,
};
const mockItem2 = {
text: 'city2',
id: 2,
};
const mockItems = [
{
text: 'group1',
children: [mockItem],
},
{
text: 'group2',
children: [mockItem],
},
];
test('should render empty TreeSelect correctly', () => {
expect(mount(TreeSelect).html()).toMatchSnapshot();
});
test('should emit click-nav event when nav item is clicked', () => {
const wrapper = mount(TreeSelect, {
props: {
items: mockItems,
},
});
const navItems = wrapper.findAll('.van-tree-select__nav-item');
navItems[1].trigger('click');
expect(wrapper.emitted('update:mainActiveIndex')?.[0]).toEqual([1]);
expect(wrapper.emitted('click-nav')?.[0]).toEqual([1]);
});
test('should emit click-item event when item is clicked', () => {
const wrapper = mount(TreeSelect, {
props: {
items: mockItems,
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[0].trigger('click');
expect(wrapper.emitted('update:activeId')?.[0]).toEqual([mockItem.id]);
expect(wrapper.emitted('click-item')?.[0]).toEqual([mockItem]);
});
test('should not emit click-nav event when disabled nav item is clicked', () => {
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
children: [mockItem],
disabled: true,
},
],
},
});
const items = wrapper.findAll('.van-tree-select__nav-item');
items[0].trigger('click');
expect(wrapper.emitted('click-nav')).toBeFalsy();
});
test('should not emit click-item event when disabled item is clicked', () => {
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
children: [
{
...mockItem,
disabled: true,
},
],
},
],
},
});
const items = wrapper.findAll('.van-tree-select__item');
items[0].trigger('click');
expect(wrapper.emitted('click-item')).toBeFalsy();
});
test('should render content slot correctly', () => {
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
},
],
},
slots: {
content: () => 'Custom Content',
},
});
expect(wrapper.html()).toMatchSnapshot();
});
test('should change height when using height prop', () => {
const wrapper = mount(TreeSelect, {
props: {
height: '100vh',
},
});
expect(wrapper.style.height).toEqual('100vh');
});
test('should render nav badge correctly', () => {
const wrapper = mount(TreeSelect, {
props: {
items: [
{
text: 'group1',
badge: 3,
},
],
},
});
expect(wrapper.html()).toMatchSnapshot();
});
test('should allow to select multiple items when activeId is array', async () => {
const wrapper = mount({
data() {
return {
activeId: [],
mainActiveIndex: 0,
items: [
{
text: 'group1',
children: [mockItem, mockItem2],
},
],
};
},
render() {
return (
<TreeSelect
v-model={[this.activeId, 'activeId']}
items={this.items}
mainActiveIndex={0}
/>
);
},
});
const items = wrapper.findAll('.van-tree-select__item');
await items[0].trigger('click');
await items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual([mockItem.id, mockItem2.id]);
await items[0].trigger('click');
await items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual([]);
});
test('should limit the selected item number when using max prop', async () => {
const wrapper = mount({
data() {
return {
activeId: [],
items: [
{
text: 'group1',
children: [mockItem, mockItem2],
},
],
};
},
render() {
return (
<TreeSelect
v-model={[this.activeId, 'activeId']}
max={1}
items={this.items}
mainActiveIndex={0}
/>
);
},
});
const items = wrapper.findAll('.van-tree-select__item');
await items[0].trigger('click');
await items[1].trigger('click');
expect(wrapper.vm.activeId).toEqual([mockItem.id]);
});
test('should allow to custom nav item className', () => {
const wrapper = mount(TreeSelect, {
props: {
mainActiveIndex: 0,
items: [
{
text: 'group1',
className: 'my-class',
children: [],
},
],
},
});
const items = wrapper.findAll('.van-tree-select__nav-item');
expect(items[0].classes()).toContain('my-class');
});
test('should change selected icon when using selected-icon prop', () => {
const wrapper = mount(TreeSelect, {
props: {
items: mockItems,
activeId: 1,
mainActiveIndex: 0,
selectedIcon: 'foo',
},
});
expect(wrapper.find('.van-tree-select__item').html()).toMatchSnapshot();
});

View File

@ -38,6 +38,8 @@ export function get(object: any, path: string): any {
return result;
}
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
export function pick<T, U extends keyof T>(
obj: T,
keys: ReadonlyArray<U>,
@ -48,5 +50,5 @@ export function pick<T, U extends keyof T>(
ret[key] = obj[key];
}
return ret;
}, {} as Pick<T, U>);
}, {} as Writeable<Pick<T, U>>);
}

View File

@ -1,4 +1,4 @@
import { isDef, isObject } from '.';
import { isDef, isObject } from './base';
type ObjectIndex = Record<string, any>;

View File

@ -36,5 +36,6 @@ declare module 'vue' {
onTouchmove?: EventHandler;
onTouchstart?: EventHandler;
onTouchcancel?: EventHandler;
onSelectSearch?: EventHandler;
}
}

View File

@ -1867,10 +1867,10 @@
"@typescript-eslint/types" "4.6.0"
eslint-visitor-keys "^2.0.0"
"@vant/cli@^3.7.1":
version "3.7.1"
resolved "https://registry.npm.taobao.org/@vant/cli/download/@vant/cli-3.7.1.tgz?cache=0&sync_timestamp=1616038598245&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vant%2Fcli%2Fdownload%2F%40vant%2Fcli-3.7.1.tgz#d79195fa6cc63fe3ba45aeba45330a4b0ed84b2b"
integrity sha1-15GV+mzGP+O6Ra66RTMKSw7YSys=
"@vant/cli@^3.8.0":
version "3.8.0"
resolved "https://registry.npm.taobao.org/@vant/cli/download/@vant/cli-3.8.0.tgz?cache=0&sync_timestamp=1617347573376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vant%2Fcli%2Fdownload%2F%40vant%2Fcli-3.8.0.tgz#0a37cf5386359c5d08690c594ee641b0bac5c2d0"
integrity sha1-CjfPU4Y1nF0IaQxZTuZBsLrFwtA=
dependencies:
"@babel/core" "^7.12.10"
"@babel/plugin-transform-object-assign" "^7.12.1"
@ -1884,7 +1884,7 @@
"@types/webpack-dev-server" "^3.11.1"
"@vant/eslint-config" "^3.2.0"
"@vant/markdown-loader" "^4.0.0"
"@vant/markdown-vetur" "^2.0.2"
"@vant/markdown-vetur" "^2.1.0"
"@vant/stylelint-config" "^1.4.2"
"@vant/touch-emulator" "^1.2.0"
"@vue/babel-plugin-jsx" "^1.0.1"
@ -1971,10 +1971,10 @@
markdown-it-anchor "^6.0.0"
transliteration "^2.1.11"
"@vant/markdown-vetur@^2.0.2":
version "2.0.2"
resolved "https://registry.npm.taobao.org/@vant/markdown-vetur/download/@vant/markdown-vetur-2.0.2.tgz#8e6be188952a2c4b0e1d626bf93f47f84ab0f22d"
integrity sha1-jmvhiJUqLEsOHWJr+T9H+Eqw8i0=
"@vant/markdown-vetur@^2.1.0":
version "2.1.0"
resolved "https://registry.npm.taobao.org/@vant/markdown-vetur/download/@vant/markdown-vetur-2.1.0.tgz?cache=0&sync_timestamp=1617347165035&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vant%2Fmarkdown-vetur%2Fdownload%2F%40vant%2Fmarkdown-vetur-2.1.0.tgz#cc49ad807dfcccca898562966d64b7a657ca3aad"
integrity sha1-zEmtgH38zMqJhWKWbWS3plfKOq0=
dependencies:
fast-glob "^3.2.2"
fs-extra "^9.0.0"
@ -11217,9 +11217,9 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
version "4.0.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"
integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==
yallist@^3.0.2:
version "3.1.1"