Skip to content

Commit

Permalink
refactor(Cascader): new cascader
Browse files Browse the repository at this point in the history
  • Loading branch information
anlyyao committed Apr 6, 2023
1 parent f57ec03 commit 1d18e26
Show file tree
Hide file tree
Showing 26 changed files with 2,968 additions and 908 deletions.
2,529 changes: 2,088 additions & 441 deletions src/cascader/__test__/__snapshots__/demo.test.jsx.snap

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/cascader/__test__/__snapshots__/index.test.jsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Vitest Snapshot v1

exports[`cascader > events > : pick 1`] = `<!--teleport start-->`;
10 changes: 8 additions & 2 deletions src/cascader/__test__/demo.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@

import { mount } from '@vue/test-utils';
import baseVue from '@/cascader/demos/base.vue';
import keysVue from '@/cascader/demos/keys.vue';
import mobileVue from '@/cascader/demos/mobile.vue';
import statusVue from '@/cascader/demos/status.vue';
import themeTabVue from '@/cascader/demos/theme-tab.vue';
import withTitleVue from '@/cascader/demos/with-title.vue';
import withValueVue from '@/cascader/demos/with-value.vue';

const mapper = {
baseVue,
keysVue,
mobileVue,
statusVue,
themeTabVue,
withTitleVue,
withValueVue,
};

describe('Cascader', () => {
Expand Down
129 changes: 63 additions & 66 deletions src/cascader/__test__/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { mount } from '@vue/test-utils';
import { describe, it, expect, vi } from 'vitest';
import Cascader from '../cascader.vue';
import { AppIcon as TIconApp, CloseIcon } from 'tdesign-icons-vue-next';
import CascaderItem from '../cascader-item.vue';
import CascaderSteps from '../steps.vue';
import Radio from '../../radio/index';
import { on } from 'events';

const prefix = 't';
const name = `${prefix}-cascader`;
Expand All @@ -13,54 +13,63 @@ const TEXT = 'tdesign-mobile-vue';
const iconFunc = () => h(TIconApp);
const options = [
{
label: '广东省',
value: 'gd',
label: '北京市',
value: '110000',
children: [
{
label: '深圳市',
value: 'sz',
value: '110100',
label: '北京市',
children: [
{
label: '南山区',
value: 'ns',
},
{
label: '福田区',
value: 'ft',
},
],
},
{
label: '广州市',
value: 'gz',
children: [
{
label: '白云区',
value: 'by',
},
{
label: '海珠区',
value: 'hz',
},
{ value: '110101', label: '东城区' },
{ value: '110102', label: '西城区' },
{ value: '110105', label: '朝阳区' },
{ value: '110106', label: '丰台区' },
{ value: '110107', label: '石景山区' },
{ value: '110108', label: '海淀区' },
{ value: '110109', label: '门头沟区' },
{ value: '110111', label: '房山区' },
{ value: '110112', label: '通州区' },
{ value: '110113', label: '顺义区' },
{ value: '110114', label: '昌平区' },
{ value: '110115', label: '大兴区' },
{ value: '110116', label: '怀柔区' },
{ value: '110117', label: '平谷区' },
{ value: '110118', label: '密云区' },
{ value: '110119', label: '延庆区' },
],
},
],
},
{
label: '福建省',
value: 'fj',
label: '天津市',
value: '120000',
children: [
{
label: '厦门市',
value: 'xm',
},
{
label: '泉州市',
value: 'qz',
value: '120100',
label: '天津市',
children: [
{ value: '120101', label: '和平区' },
{ value: '120102', label: '河东区' },
{ value: '120103', label: '河西区' },
{ value: '120104', label: '南开区' },
{ value: '120105', label: '河北区' },
{ value: '120106', label: '红桥区' },
{ value: '120110', label: '东丽区' },
{ value: '120111', label: '西青区' },
{ value: '120112', label: '津南区' },
{ value: '120113', label: '北辰区' },
{ value: '120114', label: '武清区' },
{ value: '120115', label: '宝坻区' },
{ value: '120116', label: '滨海新区' },
{ value: '120117', label: '宁河区' },
{ value: '120118', label: '静海区' },
{ value: '120119', label: '蓟州区' },
],
},
],
},
];

describe('cascader', () => {
describe('props', () => {
it(': title', async () => {
Expand Down Expand Up @@ -96,48 +105,36 @@ describe('cascader', () => {
const $title = wrapper.find(`.${name}__title`);
expect($title.text()).toBe(title);
});

it(': closeIcon', () => {
const wrapper = mount(<Cascader options={options} />, {
slots: {
closeIcon: iconFunc,
},
});
expect(wrapper.findComponent(TIconApp).exists()).toBeTruthy();
});
});

describe('events', () => {
it(': cancel', async () => {
const onCancel = vi.fn();
const wrapper = mount(<Cascader options={options} onCancel={onCancel} />);
const onClose = vi.fn();
const wrapper = mount(<Cascader options={options} onClose={onClose} />);
const $closeBtn = wrapper.find(`.${name}__close-btn`);
await $closeBtn.trigger('click');
expect(onCancel).toHaveBeenCalledTimes(1);
expect(onClose).toHaveBeenCalledTimes(1);
});

it(': pick && click-tab', async () => {
const onClickTab = vi.fn();
const onPick = vi.fn();
const wrapper = mount(<Cascader options={options} onPick={onPick} onClickTab={onClickTab} />);
const $cascaderItems = wrapper.findAllComponents(CascaderItem);
it(': pick', async () => {
let selectedValue = [];
const onPick = vi.fn((e) => {
selectedValue.push(e.value);
});
const wrapper = mount(<Cascader options={options} onPick={onPick} />);
expect(wrapper.element).toMatchSnapshot();
const $cascaderSteps = wrapper.findAll(`.${name}__step`);
expect($cascaderItems).toHaveLength(2);
// 无默认 value 值,初始化时 steps.length = 1
expect($cascaderSteps).toHaveLength(1);
const $radios = wrapper.findAllComponents(Radio);
expect( $radios).toHaveLength(options.length);

// 模拟点击 第1项 CascaderItem
// 模拟点击 第1项
const clickIndex = 0;
// await $cascaderItems[clickIndex].find(`.${name}-item`).trigger('click')
await $cascaderItems[clickIndex].trigger('click');
await $radios[clickIndex].find(`.t-radio`).trigger('click')
expect(onPick).toHaveBeenCalledTimes(1);
expect($cascaderItems[clickIndex].findAll(`.${name}-item-active-icon`)).toHaveLength(1);
expect($cascaderSteps[clickIndex].text()).toEqual(options[clickIndex].label);

// 模拟点击 第1项,step,触发 click-tab 事件名
await $cascaderSteps[clickIndex].trigger('click');
expect(onClickTab).toHaveBeenCalledTimes(1);

const $stepDot = wrapper.findAll(`.${name}__step-dot`);
expect($stepDot[clickIndex].attributes('class').includes(`${name}__step-dot--active`));
expect($radios[clickIndex].findAll(`.t-radio__icon--checked`)).toHaveLength(1);
expect (selectedValue[0]).toBe(options[0].value);
});
});
});
46 changes: 0 additions & 46 deletions src/cascader/cascader-item-prop.ts

This file was deleted.

53 changes: 0 additions & 53 deletions src/cascader/cascader-item.vue

This file was deleted.

28 changes: 28 additions & 0 deletions src/cascader/cascader.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
:: BASE_DOC ::

## API

### Cascader Props

name | type | default | description | required
-- | -- | -- | -- | --
closeBtn | Boolean / Slot / Function | true | Typescript:`boolean \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
keys | Object | - | Typescript:`KeysType`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
options | Array | [] | Typescript:`Array<CascaderOption>` | N
subTitles | Array | [] | Typescript:`Array<string>` | N
theme | String | step | options:step/tab | N
title | String / Slot / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
value | String / Number | - | `v-model` and `v-model:value` is supported | N
defaultValue | String / Number | - | uncontrolled property | N
visible | Boolean | false | \- | N
onChange | Function | | Typescript:`(value: string \| number, selectedOptions: string[]) => void`<br/> | N
onClose | Function | | Typescript:`(trigger: TriggerSource) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`<br/> | N
onPick | Function | | Typescript:`(value: string \| number, index: number) => void`<br/> | N

### Cascader Events

name | params | description
-- | -- | --
change | `(value: string \| number, selectedOptions: string[])` | \-
close | `(trigger: TriggerSource)` | [see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`<br/>
pick | `(value: string \| number, index: number)` | \-
23 changes: 15 additions & 8 deletions src/cascader/cascader.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,23 @@

名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
value | `Number | String` | [] | 选中值。支持语法糖 `v-model``v-model:value`。TS 类型:`TdCascaderItems`[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts) | N
options | Array | [] | 级联可选项。TS 类型:`TdCascaderItems`[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts) | N
closeIcon | `String | Slot` | - | 关闭 icon 图标名 | N
title | `String | Slot` | - | 标题 | N
closeBtn | Boolean / Slot / Function | true | 关闭按钮。TS 类型:`boolean \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
keys | Object | - | 用来定义 value / label 在 `options` 中对应的字段别名。TS 类型:`KeysType`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
options | Array | [] | 可选项数据源。TS 类型:`Array<CascaderOption>` | N
subTitles | Array | [] | 每级展示的次标题。TS 类型:`Array<string>` | N
theme | String | step | 展示风格。可选项:step/tab | N
title | String / Slot / Function | - | 标题。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
value | String / Number | - | 选项值。支持语法糖 `v-model``v-model:value` | N
defaultValue | String / Number | - | 选项值。非受控属性 | N
visible | Boolean | false | 是否展示 | N
onChange | Function | | TS 类型:`(value: string \| number, selectedOptions: string[]) => void`<br/>值发生变更时触发 | N
onClose | Function | | TS 类型:`(trigger: TriggerSource) => void`<br/>关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`<br/> | N
onPick | Function | | TS 类型:`(value: string \| number, index: number) => void`<br/>选择后触发 | N

### Cascader Events

名称 | 参数 | 描述
-- | -- | --
change | `(value: string | number, selectedItems: TdCascaderItems, context: { e: MouseEvent })` | 全部选项完成选择触发
pick | `(value: string | number, index: number, context: { e: MouseEvent })` | 点击选项时触发
cancel | `(context: { e: MouseEvent })` | 关闭 Cascader 触发
click-tab | `(index: number)` | 点击 tab 触发
change | `(value: string \| number, selectedOptions: string[])` | 值发生变更时触发
close | `(trigger: TriggerSource)` | 关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`<br/>
pick | `(value: string \| number, index: number)` | 选择后触发
Loading

0 comments on commit 1d18e26

Please sign in to comment.