[improvement] rename packages dir to src (#3659)

This commit is contained in:
neverland
2019-06-27 11:25:57 +08:00
committed by GitHub
parent 8489918dca
commit 75c79b7044
619 changed files with 21 additions and 21 deletions
+142
View File
@@ -0,0 +1,142 @@
<template>
<demo-section>
<demo-block :title="$t('basicUsage')">
<van-contact-card
:type="cardType"
:name="currentContact.name"
:tel="currentContact.tel"
@click="showList = true"
/>
<van-popup
v-model="showList"
position="bottom"
:lazy-render="false"
>
<van-contact-list
v-model="chosenContactId"
:list="list"
@add="onAdd"
@edit="onEdit"
@select="onSelect"
/>
</van-popup>
<van-popup
v-model="showEdit"
position="bottom"
:lazy-render="false"
>
<van-contact-edit
:contact-info="editingContact"
:is-edit="isEdit"
@save="onSave"
@delete="onDelete"
/>
</van-popup>
</demo-block>
<demo-block :title="$t('uneditable')">
<van-contact-card
type="edit"
:name="mockContact.name"
:tel="mockContact.tel"
:editable="false"
/>
</demo-block>
</demo-section>
</template>
<script>
export default {
i18n: {
'zh-CN': {
name: '张三'
},
'en-US': {
name: 'John Snow'
}
},
data() {
return {
chosenContactId: null,
editingContact: {},
showList: false,
showEdit: false,
isEdit: false,
list: []
};
},
computed: {
mockContact() {
return {
name: this.$t('name'),
tel: '13000000000',
id: 0
};
},
cardType() {
return this.chosenContactId !== null ? 'edit' : 'add';
},
currentContact() {
const id = this.chosenContactId;
return id !== null ? this.list.filter(item => item.id === id)[0] : {};
}
},
created() {
this.list.push(this.mockContact);
},
methods: {
onAdd() {
this.editingContact = { id: this.list.length };
this.isEdit = false;
this.showEdit = true;
},
onEdit(item) {
this.isEdit = true;
this.showEdit = true;
this.editingContact = item;
},
onSelect() {
this.showList = false;
},
onSave(info) {
this.showEdit = false;
this.showList = false;
if (this.isEdit) {
this.list = this.list.map(item => (item.id === info.id ? info : item));
} else {
this.list.push(info);
}
this.chosenContactId = info.id;
},
onDelete(info) {
this.showEdit = false;
this.list = this.list.filter(item => item.id !== info.id);
if (this.chosenContactId === info.id) {
this.chosenContactId = null;
}
}
}
};
</script>
<style lang="less">
.demo-contact-card {
.van-popup {
height: 100%;
background-color: #f2f2f2;
}
}
</style>
+189
View File
@@ -0,0 +1,189 @@
# Contact
### Install
``` javascript
import { ContactCard, ContactList, ContactEdit } from 'vant';
Vue
.use(ContactCard)
.use(ContactList)
.use(ContactEdit);
```
## Usage
### Basic Usage
```html
<!-- Contact Card -->
<van-contact-card
:type="cardType"
:name="currentContact.name"
:tel="currentContact.tel"
@click="showList = true"
/>
<!-- Contact List -->
<van-popup v-model="showList" position="bottom">
<van-contact-list
v-model="chosenContactId"
:list="list"
@add="onAdd"
@edit="onEdit"
@select="onSelect"
/>
</van-popup>
<!-- Contact Edit -->
<van-popup v-model="showEdit" position="bottom">
<van-contact-edit
:contact-info="editingContact"
:is-edit="isEdit"
@save="onSave"
@delete="onDelete"
/>
</van-popup>
```
``` javascript
export default {
data() {
return {
chosenContactId: null,
editingContact: {},
showList: false,
showEdit: false,
isEdit: false,
list: [{
name: 'John Snow',
tel: '13000000000',
id: 0
}]
};
},
computed: {
cardType() {
return this.chosenContactId !== null ? 'edit' : 'add';
},
currentContact() {
const id = this.chosenContactId;
return id !== null ? this.list.filter(item => item.id === id)[0] : {};
}
},
methods: {
// add contact
onAdd() {
this.editingContact = { id: this.list.length };
this.isEdit = false;
this.showEdit = true;
},
// edit contact
onEdit(item) {
this.isEdit = true;
this.showEdit = true;
this.editingContact = item;
},
// select contact
onSelect() {
this.showList = false;
},
// save contact
onSave(info) {
this.showEdit = false;
this.showList = false;
if (this.isEdit) {
this.list = this.list.map(item => item.id === info.id ? info : item);
} else {
this.list.push(info);
}
this.chosenContactId = info.id;
},
// delete contact
onDelete(info) {
this.showEdit = false;
this.list = this.list.filter(item => item.id !== info.id);
if (this.chosenContactId === info.id) {
this.chosenContactId = null;
}
}
}
};
```
### Uneditable
```html
<van-contact-card
type="edit"
name="John Snow"
tel="13000000000"
:editable="false"
/>
```
## API
### ContactCard Props
| Attribute | Description | Type | Default |
|------|------|------|------|
| type | Can be set to `add` `edit` | `String` | `add` |
| name | Name | `String` | - |
| tel | Phone | `String` | - |
| add-text | Add card text | `String` | `Add contact info` |
### ContactCard Events
| Event | Description | Arguments |
|------|------|------|
| click | Triggered when clicked | - |
### ContactList Props
| Attribute | Description | Type | Default |
|------|------|------|------|------|
| v-model | Id of chosen contact | `String | Number` | - |
| list | Contact list | `Array` | `[]` |
| add-text | Add button text | `String` | `Add new contact` |
### ContactList Events
| Event | Description | Arguments |
|------|------|------|
| add | Triggered when click add button | - |
| edit | Triggered when click edit button | item: contact objectindex |
| select | Triggered when select contact | item: contact object |
### ContactEdit Props
| Attribute | Description | Type | Default |
|------|------|------|------|------|
| contact-info | Contact Info | `Object` | `[]` |
| is-edit | Whether is editing | `Boolean` | `false` |
| is-saving | Whether to show save button loading status | `Boolean` | `false` |
| is-deleting | Whether to show delete button loading status | `Boolean` | `false` |
| tel-validator | The method to validate tel | `(tel: string) => boolean` | - |
### ContactEdit Events
| Event | Description | Arguments |
|------|------|------|
| save | Triggered when click save button | contentcontact info |
| delete | Triggered when click delete button | contentcontact info |
### Contact Data Structure
| key | Description | Type |
|------|------|------|
| id | ID | `String | Number` |
| name | Name | `String` |
| tel | Phone | `String` |
+42
View File
@@ -0,0 +1,42 @@
@import '../style/var';
.van-contact-card {
padding: @contact-card-padding;
&__value {
margin-left: 5px;
line-height: @contact-card-value-line-height;
}
&--add {
.van-contact-card__value {
line-height: @contact-card-add-icon-size;
}
.van-cell__left-icon {
color: @contact-card-add-icon-color;
font-size: @contact-card-add-icon-size;
}
}
&::before {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 2px;
background: repeating-linear-gradient(
-45deg,
#ff6c6c 0,
#ff6c6c 20%,
transparent 0,
transparent 25%,
@blue 0,
@blue 45%,
transparent 0,
transparent 50%
);
background-size: 80px;
content: '';
}
}
+68
View File
@@ -0,0 +1,68 @@
import { createNamespace } from '../utils';
import { emit, inherit } from '../utils/functional';
import Cell from '../cell';
// Types
import { CreateElement, RenderContext } from 'vue/types';
import { DefaultSlots } from '../utils/types';
const [createComponent, bem, t] = createNamespace('contact-card');
export type ContactCardProps = {
tel?: string;
name?: string;
type?: string;
addText: string;
editable: boolean;
};
function ContactCard(
h: CreateElement,
props: ContactCardProps,
slots: DefaultSlots,
ctx: RenderContext<ContactCardProps>
) {
const { type, editable } = props;
function onClick(event: Event) {
if (editable) {
emit(ctx, 'click', event);
}
}
return (
<Cell
center
border={false}
isLink={editable}
class={bem([type])}
valueClass={bem('value')}
icon={type === 'edit' ? 'contact' : 'add-square'}
onClick={onClick}
{...inherit(ctx)}
>
{type === 'add'
? props.addText || t('addText')
: [
<div>{`${t('name')}${props.name}`}</div>,
<div>{`${t('tel')}${props.tel}`}</div>
]}
</Cell>
);
}
ContactCard.props = {
tel: String,
name: String,
addText: String,
editable: {
type: Boolean,
default: true
},
type: {
type: String,
default: 'add'
}
};
export default createComponent<ContactCardProps>(ContactCard);
@@ -0,0 +1,54 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders demo correctly 1`] = `
<div>
<div>
<div class="van-cell van-cell--center van-cell--borderless van-cell--clickable van-contact-card van-contact-card--add"><i class="van-icon van-icon-add-square van-cell__left-icon">
<!----></i>
<div class="van-cell__value van-cell__value--alone van-contact-card__value">添加联系人</div><i class="van-icon van-icon-arrow van-cell__right-icon">
<!----></i>
</div>
<div class="van-popup van-popup--bottom" style="display: none;" name="van-popup-slide-bottom">
<div class="van-contact-list">
<div role="radiogroup" class="van-radio-group van-contact-list__group">
<div class="van-cell van-cell--clickable van-contact-list__item">
<div class="van-cell__value van-cell__value--alone van-contact-list__item-value">
<div role="radio" tabindex="-1" aria-checked="false" class="van-radio">
<div class="van-radio__icon van-radio__icon--round" style="font-size: 16px;"><i class="van-icon van-icon-success">
<!----></i></div><span class="van-radio__label"><div class="van-contact-list__name">张三,13000000000</div></span>
</div>
</div><i class="van-icon van-icon-edit van-contact-list__edit">
<!----></i>
</div>
</div><button class="van-button van-button--danger van-button--large van-button--square van-contact-list__add"><span class="van-button__text">新建联系人</span></button>
</div>
</div>
<div class="van-popup van-popup--bottom" style="display: none;" name="van-popup-slide-bottom">
<div class="van-contact-edit">
<div class="van-cell van-field">
<div class="van-cell__title van-field__label"><span>张三</span></div>
<div class="van-cell__value">
<div class="van-field__body"><input type="text" maxlength="30" placeholder="请填写姓名" class="van-field__control"></div>
</div>
</div>
<div class="van-cell van-field">
<div class="van-cell__title van-field__label"><span>电话</span></div>
<div class="van-cell__value">
<div class="van-field__body"><input type="tel" placeholder="请填写电话" class="van-field__control"></div>
</div>
</div>
<div class="van-contact-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button></div>
</div>
</div>
</div>
<div>
<div class="van-cell van-cell--center van-cell--borderless van-contact-card van-contact-card--edit"><i class="van-icon van-icon-contact van-cell__left-icon">
<!----></i>
<div class="van-cell__value van-cell__value--alone van-contact-card__value">
<div>张三:张三</div>
<div>电话:13000000000</div>
</div>
</div>
</div>
</div>
`;
@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ContactList render 1`] = `
<div class="van-contact-list">
<div role="radiogroup" class="van-radio-group van-contact-list__group">
<div class="van-cell van-cell--clickable van-contact-list__item">
<div class="van-cell__value van-cell__value--alone van-contact-list__item-value">
<div role="radio" tabindex="0" aria-checked="true" class="van-radio">
<div class="van-radio__icon van-radio__icon--round van-radio__icon--checked" style="font-size: 16px;"><i class="van-icon van-icon-success" style="border-color: #f44; background-color: rgb(255, 68, 68);">
<!----></i></div><span class="van-radio__label"><div class="van-contact-list__name">test123123213</div></span>
</div>
</div><i class="van-icon van-icon-edit van-contact-list__edit">
<!----></i>
</div>
</div><button class="van-button van-button--danger van-button--large van-button--square van-contact-list__add"><span class="van-button__text">新建联系人</span></button>
</div>
`;
+4
View File
@@ -0,0 +1,4 @@
import Demo from '../demo';
import demoTest from '../../../test/demo-test';
demoTest(Demo);
+143
View File
@@ -0,0 +1,143 @@
import ContactCard from '..';
import ContactList from '../../contact-list';
import ContactEdit from '../../contact-edit';
import { mount, later } from '../../../test/utils';
const contactInfo = {
name: 'test',
tel: '123123213'
};
describe('ContactCard', () => {
test('click event', () => {
const click = jest.fn();
const wrapper = mount(ContactCard, {
context: {
on: {
click
}
}
});
wrapper.trigger('click');
expect(click).toHaveBeenCalledTimes(1);
});
test('not editable', () => {
const click = jest.fn();
const wrapper = mount(ContactCard, {
propsData: {
editable: false
},
context: {
on: {
click
}
}
});
wrapper.trigger('click');
expect(click).toHaveBeenCalledTimes(0);
});
});
describe('ContactList', () => {
test('render', () => {
const wrapper = mount(ContactList, {
propsData: {
list: [contactInfo]
}
});
expect(wrapper).toMatchSnapshot();
});
test('select event', () => {
const onSelect = jest.fn();
const wrapper = mount(ContactList, {
propsData: {
list: [contactInfo]
},
context: {
on: {
select: onSelect
}
}
});
wrapper.find('.van-radio__icon').trigger('click');
expect(onSelect).toHaveBeenCalled();
});
});
describe('ContactEdit', () => {
const createComponent = () => {
const wrapper = mount(ContactEdit, {
propsData: {
contactInfo
}
});
const button = wrapper.find('.van-button');
const field = wrapper.findAll('.van-field__control');
const { errorInfo, data } = wrapper.vm;
return {
wrapper,
data,
field,
button,
errorInfo
};
};
test('valid name', () => {
const { data, field, button, errorInfo } = createComponent();
// name empty
data.name = '';
button.trigger('click');
expect(errorInfo.name).toBeTruthy();
field.at(0).trigger('focus');
expect(errorInfo.name).toBeFalsy();
});
it('valid tel', () => {
const { data, field, button, errorInfo, wrapper } = createComponent();
data.tel = '';
button.trigger('click');
expect(errorInfo.tel).toBeTruthy();
field.at(1).trigger('focus');
expect(errorInfo.tel).toBeFalsy();
data.tel = '13000000000';
button.trigger('click');
expect(errorInfo.tel).toBeFalsy();
expect(wrapper.emitted('save')[0][0]).toEqual({
name: 'test',
tel: '13000000000'
});
});
test('watch contact info', () => {
const wrapper = mount(ContactEdit);
wrapper.setProps({ contactInfo: { name: '123' } });
expect(wrapper.vm.data.name).toEqual('123');
});
test('delete contact', async () => {
const wrapper = mount(ContactEdit, {
propsData: {
isEdit: true
}
});
const deleteButton = wrapper.findAll('.van-button').at(1);
deleteButton.trigger('click');
await later();
document.querySelector('.van-dialog__confirm').click();
await later();
expect(wrapper.emitted('delete')).toBeTruthy();
});
});
+193
View File
@@ -0,0 +1,193 @@
# Contact 联系人
### 介绍
通过 Contact 组件可以实现联系人的展示、选择、编辑等功能。
### 引入
``` javascript
import { ContactCard, ContactList, ContactEdit } from 'vant';
Vue
.use(ContactCard)
.use(ContactList)
.use(ContactEdit);
```
## 代码演示
### 基础用法
```html
<!-- 联系人卡片 -->
<van-contact-card
:type="cardType"
:name="currentContact.name"
:tel="currentContact.tel"
@click="showList = true"
/>
<!-- 联系人列表 -->
<van-popup v-model="showList" position="bottom">
<van-contact-list
v-model="chosenContactId"
:list="list"
@add="onAdd"
@edit="onEdit"
@select="onSelect"
/>
</van-popup>
<!-- 联系人编辑 -->
<van-popup v-model="showEdit" position="bottom">
<van-contact-edit
:contact-info="editingContact"
:is-edit="isEdit"
@save="onSave"
@delete="onDelete"
/>
</van-popup>
```
``` javascript
export default {
data() {
return {
chosenContactId: null,
editingContact: {},
showList: false,
showEdit: false,
isEdit: false,
list: [{
name: '张三',
tel: '13000000000',
id: 0
}]
};
},
computed: {
cardType() {
return this.chosenContactId !== null ? 'edit' : 'add';
},
currentContact() {
const id = this.chosenContactId;
return id !== null ? this.list.filter(item => item.id === id)[0] : {};
}
},
methods: {
// 添加联系人
onAdd() {
this.editingContact = { id: this.list.length };
this.isEdit = false;
this.showEdit = true;
},
// 编辑联系人
onEdit(item) {
this.isEdit = true;
this.showEdit = true;
this.editingContact = item;
},
// 选中联系人
onSelect() {
this.showList = false;
},
// 保存联系人
onSave(info) {
this.showEdit = false;
this.showList = false;
if (this.isEdit) {
this.list = this.list.map(item => item.id === info.id ? info : item);
} else {
this.list.push(info);
}
this.chosenContactId = info.id;
},
// 删除联系人
onDelete(info) {
this.showEdit = false;
this.list = this.list.filter(item => item.id !== info.id);
if (this.chosenContactId === info.id) {
this.chosenContactId = null;
}
}
}
};
```
### 不可编辑
```html
<van-contact-card
type="edit"
name="张三"
tel="13000000000"
:editable="false"
/>
```
## API
### ContactCard Props
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|------|------|------|------|------|
| type | 类型,可选值为 `add` `edit` | `String` | `add` | - |
| name | 联系人姓名 | `String` | - | - |
| tel | 联系人手机号 | `String` | - | - |
| add-text | 添加时的文案提示 | `String` | `添加订单联系人信息` | - |
### ContactCard Events
| 事件名 | 说明 | 回调参数 |
|------|------|------|
| click | 点击时触发 | - |
### ContactList Props
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|------|------|------|------|------|
| v-model | 当前选中联系人的 id | `String | Number` | - | - |
| list | 联系人列表 | `Array` | `[]` | - |
| add-text | 新建按钮文案 | `String` | `新建联系人` | - |
### ContactList Events
| 事件名 | 说明 | 回调参数 |
|------|------|------|
| add | 点击新增按钮时触发 | - |
| edit | 点击编辑按钮时触发 | item: 当前联系人对象,index: 索引 |
| select | 切换选中的联系人时触发 | item: 当前联系人对象,index: 索引 |
### ContactEdit Props
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|------|------|------|------|------|
| contact-info | 联系人信息 | `Object` | `[]` | - |
| is-edit | 是否为编辑联系人 | `Boolean` | `false` | - |
| is-saving | 是否显示保存按钮加载动画 | `Boolean` | `false` | - |
| is-deleting | 是否显示删除按钮加载动画 | `Boolean` | `false` | - |
| tel-validator | 手机号格式校验函数 | `(tel: string) => boolean` | - | - |
### ContactEdit Events
| 事件名 | 说明 | 回调参数 |
|------|------|------|
| save | 点击保存按钮时触发 | content:表单内容 |
| delete | 点击删除按钮时触发 | content:表单内容 |
### 联系人数据格式
| key | 说明 | 类型 |
|------|------|------|
| id | 每位联系人的唯一标识 | `String | Number` |
| name | 联系人姓名 | `String` |
| tel | 联系人手机号 | `String | Number` |