diff --git a/docs/en-US/component/cascader.md b/docs/en-US/component/cascader.md index 6d66f30cab..f6c53fb9db 100644 --- a/docs/en-US/component/cascader.md +++ b/docs/en-US/component/cascader.md @@ -197,13 +197,13 @@ cascader/custom-tag ### Cascader Slots -| Name | Description | Scope | -| ------------------------ | ---------------------------------------------------------------------------------------------- | ----------------------------------- | -| default | the custom content of cascader node, which are current Node object and node data respectively. | ^[object]`{ node: any, data: any }` | -| empty | content when there is no matched options. | — | -| prefix ^(2.9.4) | content as Input prefix | — | -| suggestion-item ^(2.9.5) | custom content for suggestion item when searching | ^[object]`{ item: CascaderNode }` | -| tag ^(2.10.3) | custom tags style | ^[object]`{ data: Tag[] }` | +| Name | Description | Scope | +| ------------------------ | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------- | +| default | the custom content of cascader node, which are current Node object and node data respectively. | ^[object]`{ node: any, data: any }` | +| empty | content when there is no matched options. | — | +| prefix ^(2.9.4) | content as Input prefix | — | +| suggestion-item ^(2.9.5) | custom content for suggestion item when searching | ^[object]`{ item: CascaderNode }` | +| tag ^(2.10.3) | custom tags style | ^[object]`{ data: Tag[], deleteTag: (tag: Tag) => void }` | ### Cascader Exposes diff --git a/docs/en-US/component/select-v2.md b/docs/en-US/component/select-v2.md index 9c6659f99e..876b541091 100644 --- a/docs/en-US/component/select-v2.md +++ b/docs/en-US/component/select-v2.md @@ -303,16 +303,16 @@ select-v2/custom-width ### Slots -| Name | Description | Subtags | -| ---------------- | ----------------------------------------------------------------- | -------------------------------------- | -| default | Option renderer | — | -| header ^(2.5.2) | content at the top of the dropdown | — | -| footer ^(2.5.2) | content at the bottom of the dropdown | — | -| empty | content when options is empty | — | -| prefix | prefix content of input | — | -| tag ^(2.5.0) | content as Select tag, selectDisabled tag introduced in ^(2.10.3) | ^[object]`{ selectDisabled: boolean }` | -| loading ^(2.5.2) | content as Select loading | — | -| label ^(2.7.4) | content as Select label | — | +| Name | Description | Subtags | +| ---------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| default | Option renderer | — | +| header ^(2.5.2) | content at the top of the dropdown | — | +| footer ^(2.5.2) | content at the bottom of the dropdown | — | +| empty | content when options is empty | — | +| prefix | prefix content of input | — | +| tag ^(2.5.0) | content as Select tag, subTags `data`, `selectDisabled` and `deleteTag` introduced in ^(2.10.3) | ^[object]`{ data: Option[], selectDisabled: boolean, deleteTag: (event: MouseEvent, option: Option) => void }` | +| loading ^(2.5.2) | content as Select loading | — | +| label ^(2.7.4) | content as Select label | — | ### Exposes diff --git a/docs/en-US/component/select.md b/docs/en-US/component/select.md index 6ee0c3a986..055a724f45 100644 --- a/docs/en-US/component/select.md +++ b/docs/en-US/component/select.md @@ -255,16 +255,16 @@ select/custom-label ### Select Slots -| Name | Description | Subtags | -| ---------------- | ----------------------------------------------------------------- | -------------------------------------- | -| default | option component list | Option Group / Option | -| header ^(2.4.3) | content at the top of the dropdown | — | -| footer ^(2.4.3) | content at the bottom of the dropdown | — | -| prefix | content as Select prefix | — | -| empty | content when there is no options | — | -| tag ^(2.5.0) | content as Select tag, selectDisabled tag introduced in ^(2.10.3) | ^[object]`{ selectDisabled: boolean }` | -| loading ^(2.5.2) | content as Select loading | — | -| label ^(2.7.4) | content as Select label | — | +| Name | Description | Subtags | +| ---------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| default | option component list | Option Group / Option | +| header ^(2.4.3) | content at the top of the dropdown | — | +| footer ^(2.4.3) | content at the bottom of the dropdown | — | +| prefix | content as Select prefix | — | +| empty | content when there is no options | — | +| tag ^(2.5.0) | content as Select tag, subTags `data`, `selectDisabled` and `deleteTag` introduced in ^(2.10.3) | ^[object]`{ data: OptionBasic[], selectDisabled: boolean, deleteTag: (event: MouseEvent, tag: OptionPublicInstance \| OptionBasic) => void }` | +| loading ^(2.5.2) | content as Select loading | — | +| label ^(2.7.4) | content as Select label | — | ### Select Exposes diff --git a/packages/components/cascader/__tests__/cascader.test.tsx b/packages/components/cascader/__tests__/cascader.test.tsx index 65dc395a9b..fe67c43fa9 100644 --- a/packages/components/cascader/__tests__/cascader.test.tsx +++ b/packages/components/cascader/__tests__/cascader.test.tsx @@ -421,6 +421,52 @@ describe('Cascader.vue', () => { expect(wrapper.find('.el-tag').classes()).toContain('el-tag--dark') }) + test('should expose delete-tag through slot & be able to delete a value', async () => { + const value = ref(['hangzhou', 'wenzhou']) + const wrapper = _mount(() => ( + + {{ + tag: ({ data, deleteTag }: any) => + data.map((option: any) => ( +
deleteTag(option)}> + {option.text} +
+ )), + }} +
+ )) + await nextTick() + const cascader = wrapper.findComponent(Cascader) + const tags = wrapper.findAll('.no-tag') + expect(tags).toHaveLength(2) + expect(cascader.vm.modelValue).toEqual(['hangzhou', 'wenzhou']) + + await tags[0].trigger('click') + expect(wrapper.findAll('.no-tag')).toHaveLength(1) + expect(cascader.vm.modelValue).toEqual([['wenzhou']]) + }) + test('filterable', async () => { const value = ref([]) const wrapper = _mount(() => ( diff --git a/packages/components/cascader/src/cascader.vue b/packages/components/cascader/src/cascader.vue index a3e9b212a7..1028dda097 100644 --- a/packages/components/cascader/src/cascader.vue +++ b/packages/components/cascader/src/cascader.vue @@ -73,7 +73,7 @@ nsCascader.is('validate', Boolean(validateState)), ]" > - + { @@ -100,6 +101,12 @@ const createSelect = ( options.slots.default && ``) || '' + const tagSlot = + (options.slots && + options.slots.tag && + ``) || + '' + return _mount( ` ${defaultSlot} ${emptySlot} + ${tagSlot} `, { @@ -2148,6 +2156,73 @@ describe('Select', () => { expect(wrapper.findAll('.el-tag').length).toBe(1) }) + it('should return slot tag data correctly & dont have tag component', async () => { + const value = [1, 3, 5] + const wrapper = createSelect({ + data() { + return { + multiple: true, + options: [ + { label: 'Test 1', value: 1 }, + { label: 'Test 2', value: 2 }, + { label: 'Test 3', value: 3 }, + { label: 'Test 4', value: 4 }, + { label: 'Test 5', value: 5 }, + ], + value, + } + }, + slots: { + tag: ` + + {{ option.value }} - {{ option.label }} + + `, + }, + }) + await nextTick() + const slotTagEls = wrapper.findAll('.no-tag') + expect(slotTagEls).toHaveLength(3) + expect(wrapper.find('.el-tag').exists()).toBe(false) + slotTagEls.forEach((el, idx) => { + expect(el.text()).toBe(`${value[idx]} - Test ${value[idx]}`) + }) + }) + + it('should expose delete-tag through slot & be able to delete a value', async () => { + const wrapper = createSelect({ + data() { + return { + multiple: true, + options: [ + { label: 'Test 1', value: 1 }, + { label: 'Test 2', value: 2 }, + { label: 'Test 3', value: 3 }, + { label: 'Test 4', value: 4 }, + { label: 'Test 5', value: 5 }, + ], + value: [2, 3, 5], + } + }, + slots: { + tag: ` + + {{ option.value }} - {{ option.label }} + + `, + }, + }) + + await nextTick() + const slotTagEls = wrapper.findAll('.no-tag') + expect(slotTagEls).toHaveLength(3) + expect(wrapper.vm.value).toEqual([2, 3, 5]) + + await slotTagEls[0].trigger('click') + expect(wrapper.findAll('.no-tag')).toHaveLength(2) + expect(wrapper.vm.value).toEqual([3, 5]) + }) + it('should be trigger the click event', async () => { const handleClick = vi.fn() const wrapper = _mount(``, { diff --git a/packages/components/select-v2/src/select.vue b/packages/components/select-v2/src/select.vue index 3ae3b69a6d..168169d258 100644 --- a/packages/components/select-v2/src/select.vue +++ b/packages/components/select-v2/src/select.vue @@ -56,7 +56,13 @@ ), ]" > - +
{ await nextTick() expect(wrapper.findAll('.el-tag').length).toBe(1) }) + + it('should return slot tag data correctly & dont have tag component', async () => { + const value = [1, 3, 5] + const wrapper = _mount( + ` + + + + + `, + () => ({ + value, + multiple: true, + options: [ + { label: 'Test 1', value: 1 }, + { label: 'Test 2', value: 2 }, + { label: 'Test 3', value: 3 }, + { label: 'Test 4', value: 4 }, + { label: 'Test 5', value: 5 }, + ], + }) + ) + await nextTick() + const slotTagEls = wrapper.findAll('.no-tag') + expect(slotTagEls).toHaveLength(3) + expect(wrapper.find('.el-tag').exists()).toBe(false) + slotTagEls.forEach((el, idx) => { + expect(el.text()).toBe(`${value[idx]} - Test ${value[idx]}`) + }) + }) + + it('should expose delete-tag through slot & be able to delete a value', async () => { + const wrapper = _mount( + ` + + + + + `, + () => ({ + value: [2, 3, 5], + multiple: true, + options: [ + { label: 'Test 1', value: 1 }, + { label: 'Test 2', value: 2 }, + { label: 'Test 3', value: 3 }, + { label: 'Test 4', value: 4 }, + { label: 'Test 5', value: 5 }, + ], + }) + ) + await nextTick() + const slotTagEls = wrapper.findAll('.no-tag') + expect(slotTagEls).toHaveLength(3) + expect(wrapper.vm.value).toEqual([2, 3, 5]) + + await slotTagEls[0].trigger('click') + expect(wrapper.findAll('.no-tag')).toHaveLength(2) + expect(wrapper.vm.value).toEqual([3, 5]) + }) + it('It should generate accessible attributes', async () => { wrapper = _mount( ` diff --git a/packages/components/select/src/select.vue b/packages/components/select/src/select.vue index 0cb3018490..a2713c23eb 100644 --- a/packages/components/select/src/select.vue +++ b/packages/components/select/src/select.vue @@ -56,7 +56,13 @@ ), ]" > - +
{ const { t } = useLocale() @@ -521,7 +526,7 @@ export const useSelect = (props: SelectProps, emit: SelectEmits) => { const deleteTag = ( event: MouseEvent, - tag: OptionPublicInstance | SelectStates['selected'][0] + tag: OptionPublicInstance | OptionBasic ) => { const index = states.selected.indexOf(tag) if (index > -1 && !selectDisabled.value) { diff --git a/packages/theme-chalk/src/date-picker/date-table.scss b/packages/theme-chalk/src/date-picker/date-table.scss index 5e6522ab6a..3ac1d28b0d 100644 --- a/packages/theme-chalk/src/date-picker/date-table.scss +++ b/packages/theme-chalk/src/date-picker/date-table.scss @@ -157,8 +157,8 @@ border-bottom: solid 1px getCssVar('border-color-lighter'); &.#{$namespace}-date-table__week-header { - padding: 0; - width: 24px; + padding: 0; + width: 24px; } } }