From 06462b96fc4fea934504d7313a95dd9d793450e5 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Mon, 18 Oct 2021 02:11:52 +0800 Subject: [PATCH 01/12] docs(changelog): fix typo --- CHANGELOG.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index d44324980..f92e27c30 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -4,7 +4,7 @@ ### Fixes -- 修复 `n-collapse` 在 `n-collapse-item` 使用 `v-if` 是展开状态丢失,关闭 [#1387](https://github.com/TuSimple/naive-ui/issues/1387) +- 修复 `n-collapse` 在 `n-collapse-item` 使用 `v-if` 时展开状态丢失,关闭 [#1387](https://github.com/TuSimple/naive-ui/issues/1387) - 修复 `n-dialog` 的关闭按钮会被内容遮盖,关闭 [#1381](https://github.com/TuSimple/naive-ui/issues/1381) - 修复 `n-upload` 上传失败后重试时文件为 `null`,关闭 [#1316](https://github.com/TuSimple/naive-ui/issues/1316) - 修复 `n-cascader` 的 `filter` 属性不生效 From aff36db44c7aba8159fad35da953746b4633e174 Mon Sep 17 00:00:00 2001 From: songjianet <1778651752@qq.com> Date: Mon, 18 Oct 2021 09:17:02 +0800 Subject: [PATCH 02/12] test(collapse): Update collapse component test (#1362) --- src/collapse/tests/Collapse.spec.tsx | 99 +++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 9 deletions(-) diff --git a/src/collapse/tests/Collapse.spec.tsx b/src/collapse/tests/Collapse.spec.tsx index e110b3f10..298bcf096 100644 --- a/src/collapse/tests/Collapse.spec.tsx +++ b/src/collapse/tests/Collapse.spec.tsx @@ -21,6 +21,50 @@ describe('n-collapse', () => { expect(wrapper.find('.my-icon').exists()).toEqual(true) }) + it('should work with `accordion` prop', async () => { + const wrapper = mount(NCollapse, { + slots: { + default: () => [ + + {{ default: () =>
ci1
}} +
, + + {{ default: () =>
ci2
}} +
, + + {{ default: () =>
ci3
}} +
+ ] + } + }) + + const headerMains = wrapper.findAll('.n-collapse-item__header-main') + await headerMains[0].trigger('click') + await headerMains[1].trigger('click') + + expect(wrapper.findAll('.n-collapse-item__header')[0].classes()).toContain( + 'n-collapse-item__header--active' + ) + expect(wrapper.findAll('.n-collapse-item__header')[1].classes()).toContain( + 'n-collapse-item__header--active' + ) + + await wrapper.setProps({ + accordion: true + }) + + await headerMains[2].trigger('click') + expect( + wrapper.findAll('.n-collapse-item__header')[0].classes() + ).not.toContain('n-collapse-item__header--active') + expect( + wrapper.findAll('.n-collapse-item__header')[1].classes() + ).not.toContain('n-collapse-item__header--active') + expect(wrapper.findAll('.n-collapse-item__header')[2].classes()).toContain( + 'n-collapse-item__header--active' + ) + }) + it('should work with `arrow-placement` prop', async () => { const wrapper = mount(NCollapse, { slots: { @@ -38,28 +82,40 @@ describe('n-collapse', () => { }) it('should work with nested structure', async () => { - mount(NCollapse, { + const wrapper = mount(NCollapse, { slots: { default: () => h( NCollapseItem, - { name: '1', title: 'test1' }, + { name: '1' }, { default: () => h(NCollapse, null, { - default: () => h(NCollapseItem, { name: '2', title: 'test2' }) + default: () => h(NCollapseItem, { name: '2' }) }) } ) } }) - // todo: test display-directive - // I wanted to test this function, but I was bothered by the + await wrapper.find('.n-collapse-item__header-main').trigger('click') + expect(wrapper.find('.n-collapse-item__header').classes()).toContain( + 'n-collapse-item__header--active' + ) + await wrapper + .find('.n-collapse-item__content-wrapper') + .find('.n-collapse-item__header-main') + .trigger('click') + expect( + wrapper + .find('.n-collapse-item__content-wrapper') + .find('.n-collapse-item__header') + .classes() + ).toContain('n-collapse-item__header--active') }) it('should work with `display-directive` prop', async () => { - mount(NCollapse, { + const wrapper = mount(NCollapse, { props: { displayDirective: 'show' }, @@ -67,13 +123,27 @@ describe('n-collapse', () => { default: () => h( NCollapseItem, - { name: '1', title: 'test' }, + { name: '1' }, { default: () => h('div', null, { default: () => 'test' }) } ) } - // todo: test display-directive - // I wanted to test this function, but I was bothered by the }) + + await wrapper.find('.n-collapse-item__header-main').trigger('click') + await wrapper.find('.n-collapse-item__header-main').trigger('click') + expect( + wrapper.find('.n-collapse-item__content-wrapper').attributes('style') + ).toBe('display: none;') + + await wrapper.setProps({ + displayDirective: 'if' + }) + + await wrapper.find('.n-collapse-item__header-main').trigger('click') + await wrapper.find('.n-collapse-item__header-main').trigger('click') + expect(wrapper.find('.n-collapse-item__content-wrapper').exists()).toBe( + false + ) }) it('should work with `on-item-header-click` prop', async () => { @@ -149,4 +219,15 @@ describe('n-collapse', () => { expect(wrapper.find('.ci1').isVisible()).toEqual(true) expect(wrapper.find('.ci2').exists()).toEqual(false) }) + + it('should work with collapseItem component `title` prop', async () => { + const wrapper = mount(NCollapse, { + slots: { + default: () => + } + }) + + await wrapper.find('.n-collapse-item__header-main').trigger('click') + expect(wrapper.find('.n-collapse-item__header-main').text()).toBe('test') + }) }) From 710410cae8b5eb9f3a68f81e2f2f1fe5a82401fe Mon Sep 17 00:00:00 2001 From: XieZongChen <46394163+amadeus711@users.noreply.github.com> Date: Sun, 17 Oct 2021 21:04:50 -0500 Subject: [PATCH 03/12] test(data-table): update test (#1392) --- src/data-table/tests/DataTable.spec.tsx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/data-table/tests/DataTable.spec.tsx b/src/data-table/tests/DataTable.spec.tsx index 15b07578c..aaf4538fc 100644 --- a/src/data-table/tests/DataTable.spec.tsx +++ b/src/data-table/tests/DataTable.spec.tsx @@ -1087,4 +1087,26 @@ describe('props.columns', () => { 'test-age' ) }) + + it('should work with `render` prop', async () => { + const columns: DataTableColumns = [ + { + title: 'Name', + key: 'name', + render (rowData: any, rowIndex: number) { + return `${String(rowData.name)}-${rowIndex}` + } + } + ] + const data = new Array(5).fill(0).map((_, index) => { + return { + name: index + } + }) + const rowKey = (row: any): number => row.name + const wrapper = mount(() => ( + + )) + expect(wrapper.find('tbody [data-col-key="name"]').text()).toContain('0-0') + }) }) From 68a804b426f580ca7c5d73debfce499b651871ac Mon Sep 17 00:00:00 2001 From: songjianet <1778651752@qq.com> Date: Tue, 19 Oct 2021 00:04:34 +0800 Subject: [PATCH 04/12] test(carousel): update test (#1335) * test(carousel): Update carousel component test * test(carousel): Update carousel component test * test(carousel): Update carousel component test --- .../{Carousel.spec.ts => Carousel.spec.tsx} | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) rename src/carousel/tests/{Carousel.spec.ts => Carousel.spec.tsx} (75%) diff --git a/src/carousel/tests/Carousel.spec.ts b/src/carousel/tests/Carousel.spec.tsx similarity index 75% rename from src/carousel/tests/Carousel.spec.ts rename to src/carousel/tests/Carousel.spec.tsx index f7c4efdb2..29dcafc49 100644 --- a/src/carousel/tests/Carousel.spec.ts +++ b/src/carousel/tests/Carousel.spec.tsx @@ -59,6 +59,36 @@ describe('n-carousel', () => { } }) + it('should work with `interval` prop', async () => { + const wrapper = mount(NCarousel, { + props: { + interval: 100, + autoplay: true + }, + slots: { + default: () => { + return [...Array(3).keys()].map((i) => { + return h('div', {}, i.toString()) + }) + } + } + }) + + await sleep(100) + expect( + wrapper + .find('.n-carousel__slides') + .find('[data-index="2"]') + .attributes('aria-hidden') + ).toBe('false') + expect( + wrapper + .find('.n-carousel__dots') + .findAll('.n-carousel__dot')[1] + .attributes('aria-selected') + ).toBe('true') + }) + it('should work with `showArrow` prop', async () => { const wrapper = mount(NCarousel) @@ -113,20 +143,18 @@ describe('n-carousel', () => { expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false') - wrapper - .find('.n-carousel__arrow--right') - .trigger('click') - .then(async () => { - expect(slidesDOMArray[2].attributes('aria-hidden')).toBe('false') - await sleep(1000) - nextTick(() => { - wrapper - .find('.n-carousel__arrow--left') - .trigger('click') - .then(() => { - expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false') - }) + await wrapper.find('.n-carousel__arrow--right').trigger('click') + + expect(slidesDOMArray[2].attributes('aria-hidden')).toBe('false') + + await sleep(1000) + await nextTick(() => { + void wrapper + .find('.n-carousel__arrow--left') + .trigger('click') + .then(() => { + expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false') }) - }) + }) }) }) From 1db7127f7070d643ffbd4e78d036b0c1d2819106 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Tue, 19 Oct 2021 00:16:00 +0800 Subject: [PATCH 05/12] test(carousel): flatten promise code --- src/carousel/tests/Carousel.spec.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/carousel/tests/Carousel.spec.tsx b/src/carousel/tests/Carousel.spec.tsx index 29dcafc49..1f0bcf25a 100644 --- a/src/carousel/tests/Carousel.spec.tsx +++ b/src/carousel/tests/Carousel.spec.tsx @@ -148,13 +148,13 @@ describe('n-carousel', () => { expect(slidesDOMArray[2].attributes('aria-hidden')).toBe('false') await sleep(1000) - await nextTick(() => { - void wrapper - .find('.n-carousel__arrow--left') - .trigger('click') - .then(() => { - expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false') - }) - }) + await nextTick() + + void wrapper + .find('.n-carousel__arrow--left') + .trigger('click') + .then(() => { + expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false') + }) }) }) From 7b3b1c99c8a6c02ad6ed39f104fe429efc92c2bf Mon Sep 17 00:00:00 2001 From: songjianet <1778651752@qq.com> Date: Wed, 20 Oct 2021 09:15:59 +0800 Subject: [PATCH 06/12] test(descriptions): Update descriptions component test (#1400) --- src/descriptions/tests/Descriptions.spec.ts | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/descriptions/tests/Descriptions.spec.ts b/src/descriptions/tests/Descriptions.spec.ts index fdd92046f..4da9e0d87 100644 --- a/src/descriptions/tests/Descriptions.spec.ts +++ b/src/descriptions/tests/Descriptions.spec.ts @@ -129,6 +129,7 @@ describe('n-descriptions', () => { expect(wrapper.find('.n-descriptions-header').exists()).toBe(true) expect(wrapper.find('.n-descriptions-header').text()).toBe('test') }) + it('should work with `separator` prop', async () => { const wrapper = mount(NDescriptions, { props: { @@ -141,4 +142,34 @@ describe('n-descriptions', () => { await wrapper.setProps({ separator: '/' }) expect(wrapper.find('.n-descriptions-separator').text()).toEqual('/') }) + + it('should work with `content-style` prop', () => { + const wrapper = mount(NDescriptions, { + props: { + contentStyle: { backgroundColor: 'red' } + }, + slots: { + default: () => h(NDescriptionsItem, {}, 'test') + } + }) + + expect( + wrapper.find('.n-descriptions-table-content').attributes('style') + ).toBe('background-color: red;') + }) + + it('should work with `label-style` prop', () => { + const wrapper = mount(NDescriptions, { + props: { + labelStyle: { fontSize: '30px' } + }, + slots: { + default: () => h(NDescriptionsItem, {}, 'test') + } + }) + + expect( + wrapper.find('.n-descriptions-table-header').attributes('style') + ).toBe('font-size: 30px;') + }) }) From 7686b69e2a128553e2611b0b6679e00de30ed032 Mon Sep 17 00:00:00 2001 From: doom-9 <65016011+doom-9@users.noreply.github.com> Date: Wed, 20 Oct 2021 13:47:57 +0800 Subject: [PATCH 07/12] feat(date-picker): month-picker i18n --- src/date-picker/src/DatePicker.tsx | 2 ++ src/locales/common/enUS.ts | 1 + src/locales/common/jaJP.ts | 1 + src/locales/common/ruRU.ts | 1 + src/locales/common/ukUA.ts | 1 + src/locales/common/zhCN.ts | 1 + 6 files changed, 7 insertions(+) diff --git a/src/date-picker/src/DatePicker.tsx b/src/date-picker/src/DatePicker.tsx index 81bde503d..6b78c02fa 100644 --- a/src/date-picker/src/DatePicker.tsx +++ b/src/date-picker/src/DatePicker.tsx @@ -206,6 +206,8 @@ export default defineComponent({ return localeRef.value.datePlaceholder } else if (props.type === 'datetime') { return localeRef.value.datetimePlaceholder + } else if (props.type === 'month') { + return localeRef.value.monthPlaceholder } return props.placeholder } else { diff --git a/src/locales/common/enUS.ts b/src/locales/common/enUS.ts index 7b266a0ed..09bbb0eba 100644 --- a/src/locales/common/enUS.ts +++ b/src/locales/common/enUS.ts @@ -30,6 +30,7 @@ const enUS = { selectDate: 'Select Date', datePlaceholder: 'Select Date', datetimePlaceholder: 'Select Date and Time', + monthPlaceholder: 'Select Month', startDatePlaceholder: 'Start Date', endDatePlaceholder: 'End Date', startDatetimePlaceholder: 'Start Date and Time', diff --git a/src/locales/common/jaJP.ts b/src/locales/common/jaJP.ts index 9a675815d..97d6afe41 100644 --- a/src/locales/common/jaJP.ts +++ b/src/locales/common/jaJP.ts @@ -32,6 +32,7 @@ const jaJP: NLocale = { selectDate: '日付を選択', datePlaceholder: '日付を選択', datetimePlaceholder: '選択', + monthPlaceholder: '月を選択', startDatePlaceholder: '開始日', endDatePlaceholder: '終了日', startDatetimePlaceholder: '開始時間', diff --git a/src/locales/common/ruRU.ts b/src/locales/common/ruRU.ts index 45aca257b..aa4f37295 100644 --- a/src/locales/common/ruRU.ts +++ b/src/locales/common/ruRU.ts @@ -32,6 +32,7 @@ const ruRu: NLocale = { selectDate: 'Выбрать дату', datePlaceholder: 'Выбрать дату', datetimePlaceholder: 'Выбрать дату и время', + monthPlaceholder: 'Выберите месяц', startDatePlaceholder: 'Дата начала', endDatePlaceholder: 'Дата окончания', startDatetimePlaceholder: 'Дата и время начала', diff --git a/src/locales/common/ukUA.ts b/src/locales/common/ukUA.ts index 9e7aa3021..266f7767c 100644 --- a/src/locales/common/ukUA.ts +++ b/src/locales/common/ukUA.ts @@ -32,6 +32,7 @@ const ukUA: NLocale = { selectDate: 'Обрати дату', datePlaceholder: 'Обрати дату', datetimePlaceholder: 'Обрати дату і час', + monthPlaceholder: 'Виберіть місяць', startDatePlaceholder: 'Дата початку', endDatePlaceholder: 'Дата завершення', startDatetimePlaceholder: 'Дата і час початку', diff --git a/src/locales/common/zhCN.ts b/src/locales/common/zhCN.ts index e5a16722d..d4aef4714 100644 --- a/src/locales/common/zhCN.ts +++ b/src/locales/common/zhCN.ts @@ -32,6 +32,7 @@ const zhCN: NLocale = { selectDate: '选择日期', datePlaceholder: '选择日期', datetimePlaceholder: '选择日期时间', + monthPlaceholder: '选择月份', startDatePlaceholder: '开始日期', endDatePlaceholder: '结束日期', startDatetimePlaceholder: '开始日期时间', From 2c530b56da9f99809d4b69488256680be302f3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=AD=94=E7=8E=8B?= <40223749+LYErin@users.noreply.github.com> Date: Wed, 20 Oct 2021 23:22:40 +0800 Subject: [PATCH 08/12] feat(tabs): add on-before-leave prop (#1394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(tabs): add on-before-leave prop * feat: demo引入属性优化 * feat: 优化tab加载 * feat: 优化tab加载 * feat: 处理新tab打开中断旧导航 Co-authored-by: unknown --- CHANGELOG.en-US.md | 6 ++++ CHANGELOG.zh-CN.md | 6 ++++ src/tabs/demos/enUS/before-leave.demo.md | 33 ++++++++++++++++++++++ src/tabs/demos/enUS/index.demo-entry.md | 2 ++ src/tabs/demos/zhCN/before-leave.demo.md | 36 ++++++++++++++++++++++++ src/tabs/demos/zhCN/index.demo-entry.md | 2 ++ src/tabs/src/Tab.tsx | 26 ++++++++++++++++- src/tabs/src/Tabs.tsx | 21 ++++++++++++++ src/tabs/src/interface.ts | 12 ++++++++ 9 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/tabs/demos/enUS/before-leave.demo.md create mode 100644 src/tabs/demos/zhCN/before-leave.demo.md diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index c3e1f835c..317baf86f 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -1,5 +1,11 @@ # CHANGELOG +## Pending + +### Feats + +- `n-tabs` add `on-before-leave` prop, closes [#1337](https://github.com/TuSimple/naive-ui/issues/1337). + ## 2.19.9 (2021-10-18) ### Fixes diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index f92e27c30..28ea0c630 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -1,5 +1,11 @@ # CHANGELOG +## Pending + +### Feats + +- `n-tabs` 新增 `on-before-leave` 属性,关闭 [#1337](https://github.com/TuSimple/naive-ui/issues/1337) + ## 2.19.9 (2021-10-18) ### Fixes diff --git a/src/tabs/demos/enUS/before-leave.demo.md b/src/tabs/demos/enUS/before-leave.demo.md new file mode 100644 index 000000000..1c1270dfd --- /dev/null +++ b/src/tabs/demos/enUS/before-leave.demo.md @@ -0,0 +1,33 @@ +# Hook function before switching tab + +```html + + Wonderwall + Hey Jude + My faviur + +``` + +```js +import { defineComponent } from 'vue' +import { useMessage } from 'naive-ui' + +export default defineComponent({ + setup () { + const message = useMessage() + return { + handleBeforeLeave: (tab, oldTab) => { + if (tab === 'jay chou') message.info('Can not leave!') + return tab !== 'jay chou' + }, + handleUpdateValue: (activeName) => { + message.info(activeName) + } + } + } +}) +``` diff --git a/src/tabs/demos/enUS/index.demo-entry.md b/src/tabs/demos/enUS/index.demo-entry.md index 1fd9f493b..57d76b19e 100644 --- a/src/tabs/demos/enUS/index.demo-entry.md +++ b/src/tabs/demos/enUS/index.demo-entry.md @@ -14,6 +14,7 @@ prefix display-directive addable line-debug +before-leave ``` ## API @@ -33,6 +34,7 @@ line-debug | type | `'bar' \| 'line' \| 'card' \| 'segment'` | `'bar'` | Tabs type. | | value | `string \| number` | `undefined` | Value in controlled mode. | | on-add | `() => void` | `undefined` | Callback function triggered when add tag. | +| on-before-leave | `(activeName: string \| number, oldActiveName: string \| number \| null) => boolean \| Promise` | `undefined` | hook function before switching tab. | | on-close | `(name: string \| number) => void` | `undefined` | Callback function triggered when close tag. | | on-update:value | `(value: string \| number) => void` | `undefined` | Callback function triggered when the value changes. | diff --git a/src/tabs/demos/zhCN/before-leave.demo.md b/src/tabs/demos/zhCN/before-leave.demo.md new file mode 100644 index 000000000..3f16dd79c --- /dev/null +++ b/src/tabs/demos/zhCN/before-leave.demo.md @@ -0,0 +1,36 @@ +# 切换标签前的钩子函数 + +```html + + Oasis + Oasis + the beatles + My faviur + +``` + +```js +import { defineComponent, ref } from 'vue' +import { useMessage } from 'naive-ui' + +export default defineComponent({ + setup () { + const message = useMessage() + const OasisRef = ref('正在加载中...') + return { + Oasis: OasisRef, + handleBeforeLeave: (tab, oldTab) => { + if (tab === 'jay chou') message.info('Can not leave!') + return tab !== 'jay chou' + }, + handleUpdateValue: (activeName) => { + message.info(activeName) + } + } + } +}) +``` diff --git a/src/tabs/demos/zhCN/index.demo-entry.md b/src/tabs/demos/zhCN/index.demo-entry.md index ddb75952b..f70bcc080 100644 --- a/src/tabs/demos/zhCN/index.demo-entry.md +++ b/src/tabs/demos/zhCN/index.demo-entry.md @@ -16,6 +16,7 @@ addable line-debug style-inherit-debug shadow-debug +before-leave ``` ## API @@ -35,6 +36,7 @@ shadow-debug | type | `'bar' \| 'line' \| 'card' \| 'segment'` | `'bar'` | 标签类型 | | value | `string \| number` | `undefined` | 受控模式下的值 | | on-add | `() => void` | `undefined` | 添加标签的回调函数 | +| on-before-leave | `(activeName: string \| number, oldActiveName: string \| number \| null) => boolean \| Promise` | `undefined` | 切换标签之前的钩子函数 | | on-close | `(name: string \| number) => void` | `undefined` | 关闭标签的回调函数 | | on-update:value | `(value: string \| number) => void` | `undefined` | 选中发生改变时的回调函数 | diff --git a/src/tabs/src/Tab.tsx b/src/tabs/src/Tab.tsx index 4743f5deb..74579f135 100644 --- a/src/tabs/src/Tab.tsx +++ b/src/tabs/src/Tab.tsx @@ -21,8 +21,11 @@ export default defineComponent({ typeRef, closableRef, tabStyleRef, + tabIdRef, handleAdd, + handleBeforeLeave, handleTabClick, + setTabId, handleClose // eslint-disable-next-line @typescript-eslint/no-non-null-assertion } = inject(tabsInjectionKey)! @@ -48,7 +51,28 @@ export default defineComponent({ handleAdd() return } - handleTabClick(props.name) + const id = tabIdRef.value ? tabIdRef.value.id + 1 : 1 + setTabId(props.name, id) + if (props.name !== valueRef.value) { + const result = handleBeforeLeave(props.name, valueRef.value) + if (typeof result === 'boolean') { + if (result) handleTabClick(props.name) + } else { + result.then( + () => { + if ( + tabIdRef.value.tab === props.name && + tabIdRef.value.id === id + ) { + handleTabClick(props.name) + } + }, + () => { + // not allowed to change tab + } + ) + } + } } } }, diff --git a/src/tabs/src/Tabs.tsx b/src/tabs/src/Tabs.tsx index a1c8f48ff..4962ba529 100644 --- a/src/tabs/src/Tabs.tsx +++ b/src/tabs/src/Tabs.tsx @@ -28,6 +28,8 @@ import { Addable, OnClose, OnCloseImpl, + BeforeLeave, + BeforeLeaveImpl, tabsInjectionKey, TabsType } from './interface' @@ -58,6 +60,7 @@ const tabsProps = { type: Number, default: 0 }, + onBeforeLeave: [Function, Array] as PropType>, onAdd: Function as PropType<() => void>, 'onUpdate:value': [Function, Array] as PropType>, onUpdateValue: [Function, Array] as PropType>, @@ -135,6 +138,10 @@ export default defineComponent({ compitableValueRef, uncontrolledValueRef ) + const tabIdRef = ref<{ tab: string | number | null, id: number }>({ + tab: mergedValueRef.value, + id: 0 + }) const tabWrapperStyleRef = computed(() => { if (!props.justifyContent || props.type === 'card') return undefined @@ -177,9 +184,20 @@ export default defineComponent({ updateBarStyle(tabEl) } } + function handleBeforeLeave ( + activeName: string | number, + oldActiveName: string | number | null + ): boolean | Promise { + const { onBeforeLeave } = props + if (!onBeforeLeave) return true + return (onBeforeLeave as BeforeLeaveImpl)(activeName, oldActiveName) + } function handleTabClick (panelName: string | number): void { doUpdateValue(panelName) } + function setTabId (tab: string | number, id: number): void { + tabIdRef.value = { tab, id } + } function doUpdateValue (panelName: string | number): void { const { onActiveNameChange, @@ -275,7 +293,10 @@ export default defineComponent({ typeRef: toRef(props, 'type'), closableRef: toRef(props, 'closable'), valueRef: mergedValueRef, + tabIdRef, + handleBeforeLeave, handleTabClick, + setTabId, handleClose, handleAdd }) diff --git a/src/tabs/src/interface.ts b/src/tabs/src/interface.ts index 29269fae8..2f08076f4 100644 --- a/src/tabs/src/interface.ts +++ b/src/tabs/src/interface.ts @@ -8,6 +8,15 @@ export type OnUpdateValueImpl = (value: string | number) => void export type OnClose = (name: string & number) => void export type OnCloseImpl = (name: string | number) => void +export type BeforeLeave = ( + activeName: string & number, + oldActiveName: string & number & null +) => boolean | Promise +export type BeforeLeaveImpl = ( + activeName: string | number, + oldActiveName: string | number | null +) => boolean | Promise + export interface TabsInjection { mergedClsPrefixRef: Ref valueRef: Ref @@ -15,7 +24,10 @@ export interface TabsInjection { closableRef: Ref tabStyleRef: Ref paneStyleRef: Ref + tabIdRef: Ref<{ tab: string | number | null, id: number }> + handleBeforeLeave: BeforeLeaveImpl handleTabClick: (panelName: string | number) => void + setTabId: (tab: string | number, id: number) => void handleClose: (panelName: string | number) => void handleAdd: () => void } From fb650816a9d355e2785848107f8ad05ae60c6d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B9=90=E8=81=AA?= Date: Thu, 21 Oct 2021 00:10:29 +0800 Subject: [PATCH 09/12] refactor(tabs): on-before-leave prop --- package.json | 1 - src/tabs/demos/enUS/before-leave.demo.md | 34 +++++++++++----- src/tabs/demos/enUS/card.demo.md | 2 +- src/tabs/demos/enUS/display-directive.demo.md | 2 +- src/tabs/demos/enUS/flex-label.demo.md | 2 +- src/tabs/demos/enUS/index.demo-entry.md | 2 +- src/tabs/demos/enUS/line-debug.demo.md | 2 +- src/tabs/demos/enUS/prefix.demo.md | 2 +- src/tabs/demos/zhCN/before-leave.demo.md | 39 ++++++++++++------- src/tabs/demos/zhCN/index.demo-entry.md | 2 +- src/tabs/src/Tab.tsx | 38 ++++++++---------- src/tabs/src/Tabs.tsx | 27 +++---------- src/tabs/src/interface.ts | 17 ++++---- 13 files changed, 88 insertions(+), 82 deletions(-) diff --git a/package.json b/package.json index 233872e48..1664da095 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,6 @@ "eslint-plugin-markdown": "^2.0.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", - "eslint-plugin-standard": "^5.0.0", "eslint-plugin-vue": "^7.6.0", "express": "^4.17.1", "fs-extra": "^10.0.0", diff --git a/src/tabs/demos/enUS/before-leave.demo.md b/src/tabs/demos/enUS/before-leave.demo.md index 1c1270dfd..9c767230f 100644 --- a/src/tabs/demos/enUS/before-leave.demo.md +++ b/src/tabs/demos/enUS/before-leave.demo.md @@ -1,14 +1,17 @@ -# Hook function before switching tab +# Hook before tab switching + +You can prevent or postpone tab switching. ```html - Wonderwall - Hey Jude - My faviur + +1s + ??? + Just so so ``` @@ -20,12 +23,25 @@ export default defineComponent({ setup () { const message = useMessage() return { - handleBeforeLeave: (tab, oldTab) => { - if (tab === 'jay chou') message.info('Can not leave!') - return tab !== 'jay chou' + handleBeforeLeave: (tabName) => { + switch (tabName) { + case 'not-allowed': + message.error('Not allowed') + return false + case 'wait': + return new Promise((resolve) => { + const messageInstance = message.loading('Wait for 1s') + setTimeout(() => { + messageInstance.destroy() + resolve(true) + }, 1000) + }) + default: + return true + } }, - handleUpdateValue: (activeName) => { - message.info(activeName) + handleUpdateValue: (value) => { + message.info(value) } } } diff --git a/src/tabs/demos/enUS/card.demo.md b/src/tabs/demos/enUS/card.demo.md index 32943c6a8..5e5004a2b 100644 --- a/src/tabs/demos/enUS/card.demo.md +++ b/src/tabs/demos/enUS/card.demo.md @@ -1,4 +1,4 @@ -# Card Type +# Card type Set `type='card'`. diff --git a/src/tabs/demos/enUS/display-directive.demo.md b/src/tabs/demos/enUS/display-directive.demo.md index f69ac2ce5..9dd4ed01e 100644 --- a/src/tabs/demos/enUS/display-directive.demo.md +++ b/src/tabs/demos/enUS/display-directive.demo.md @@ -1,4 +1,4 @@ -# Display Directive +# Display directive You can set tab-panel's display directive to `if` or `show`. When use show, the tab-panel's content won't be reset after tab changes. diff --git a/src/tabs/demos/enUS/flex-label.demo.md b/src/tabs/demos/enUS/flex-label.demo.md index e7b21fce5..100f12457 100644 --- a/src/tabs/demos/enUS/flex-label.demo.md +++ b/src/tabs/demos/enUS/flex-label.demo.md @@ -1,4 +1,4 @@ -# Flex Tabs +# Flex tabs Only works with `line` typed tabs. diff --git a/src/tabs/demos/enUS/index.demo-entry.md b/src/tabs/demos/enUS/index.demo-entry.md index 57d76b19e..d4bee66fb 100644 --- a/src/tabs/demos/enUS/index.demo-entry.md +++ b/src/tabs/demos/enUS/index.demo-entry.md @@ -34,7 +34,7 @@ before-leave | type | `'bar' \| 'line' \| 'card' \| 'segment'` | `'bar'` | Tabs type. | | value | `string \| number` | `undefined` | Value in controlled mode. | | on-add | `() => void` | `undefined` | Callback function triggered when add tag. | -| on-before-leave | `(activeName: string \| number, oldActiveName: string \| number \| null) => boolean \| Promise` | `undefined` | hook function before switching tab. | +| on-before-leave | `(activeName: string \| number, oldActiveName: string \| number \| null) => boolean \| Promise` | `undefined` | Hook function before switching tab. Returning `false` or promise resolving `false` or promise rejection will prevent tab switching. | | on-close | `(name: string \| number) => void` | `undefined` | Callback function triggered when close tag. | | on-update:value | `(value: string \| number) => void` | `undefined` | Callback function triggered when the value changes. | diff --git a/src/tabs/demos/enUS/line-debug.demo.md b/src/tabs/demos/enUS/line-debug.demo.md index a4d3331d4..ce58efbd6 100644 --- a/src/tabs/demos/enUS/line-debug.demo.md +++ b/src/tabs/demos/enUS/line-debug.demo.md @@ -1,4 +1,4 @@ -# Line Debug +# Line debug ```html Set Name to the Beatles diff --git a/src/tabs/demos/enUS/prefix.demo.md b/src/tabs/demos/enUS/prefix.demo.md index 00f277fe0..716990feb 100644 --- a/src/tabs/demos/enUS/prefix.demo.md +++ b/src/tabs/demos/enUS/prefix.demo.md @@ -1,4 +1,4 @@ -# Prefix & Suffix +# Prefix & suffix Use `prefix` & `suffix` slot to add prefix & suffix. diff --git a/src/tabs/demos/zhCN/before-leave.demo.md b/src/tabs/demos/zhCN/before-leave.demo.md index 3f16dd79c..466ed3e06 100644 --- a/src/tabs/demos/zhCN/before-leave.demo.md +++ b/src/tabs/demos/zhCN/before-leave.demo.md @@ -1,34 +1,47 @@ -# 切换标签前的钩子函数 +# 切换 Tab 前的回调 + +你可以延迟或阻止 Tab 切换。 ```html - Oasis - Oasis - the beatles - My faviur + +1s + ??? + 就那么回事吧 ``` ```js -import { defineComponent, ref } from 'vue' +import { defineComponent } from 'vue' import { useMessage } from 'naive-ui' export default defineComponent({ setup () { const message = useMessage() - const OasisRef = ref('正在加载中...') return { - Oasis: OasisRef, - handleBeforeLeave: (tab, oldTab) => { - if (tab === 'jay chou') message.info('Can not leave!') - return tab !== 'jay chou' + handleBeforeLeave: (tabName) => { + switch (tabName) { + case 'not-allowed': + message.error('不许进来') + return false + case 'wait': + return new Promise((resolve) => { + const messageInstance = message.loading('Wait for 1s') + setTimeout(() => { + messageInstance.destroy() + resolve(true) + }, 1000) + }) + default: + return true + } }, - handleUpdateValue: (activeName) => { - message.info(activeName) + handleUpdateValue: (value) => { + message.info(value) } } } diff --git a/src/tabs/demos/zhCN/index.demo-entry.md b/src/tabs/demos/zhCN/index.demo-entry.md index f70bcc080..95628b636 100644 --- a/src/tabs/demos/zhCN/index.demo-entry.md +++ b/src/tabs/demos/zhCN/index.demo-entry.md @@ -36,7 +36,7 @@ before-leave | type | `'bar' \| 'line' \| 'card' \| 'segment'` | `'bar'` | 标签类型 | | value | `string \| number` | `undefined` | 受控模式下的值 | | on-add | `() => void` | `undefined` | 添加标签的回调函数 | -| on-before-leave | `(activeName: string \| number, oldActiveName: string \| number \| null) => boolean \| Promise` | `undefined` | 切换标签之前的钩子函数 | +| on-before-leave | `(name: string \| number, oldName: string \| number \| null) => boolean \| Promise` | `undefined` | 切换标签之前的钩子函数,返回 `false` 或 promise resolve `false` 或 promise reject 会组织切换 | | on-close | `(name: string \| number) => void` | `undefined` | 关闭标签的回调函数 | | on-update:value | `(value: string \| number) => void` | `undefined` | 选中发生改变时的回调函数 | diff --git a/src/tabs/src/Tab.tsx b/src/tabs/src/Tab.tsx index 74579f135..2e5d45d16 100644 --- a/src/tabs/src/Tab.tsx +++ b/src/tabs/src/Tab.tsx @@ -2,7 +2,7 @@ import { h, defineComponent, inject, computed } from 'vue' import { AddIcon } from '../../_internal/icons' import { NBaseClose, NBaseIcon } from '../../_internal' import { render } from '../../_utils' -import { tabsInjectionKey } from './interface' +import { OnBeforeLeaveImpl, tabsInjectionKey } from './interface' import { tabPaneProps } from './TabPane' export default defineComponent({ @@ -21,11 +21,10 @@ export default defineComponent({ typeRef, closableRef, tabStyleRef, - tabIdRef, + nextTabNameRef, + onBeforeLeaveRef, handleAdd, - handleBeforeLeave, handleTabClick, - setTabId, handleClose // eslint-disable-next-line @typescript-eslint/no-non-null-assertion } = inject(tabsInjectionKey)! @@ -51,26 +50,21 @@ export default defineComponent({ handleAdd() return } - const id = tabIdRef.value ? tabIdRef.value.id + 1 : 1 - setTabId(props.name, id) - if (props.name !== valueRef.value) { - const result = handleBeforeLeave(props.name, valueRef.value) - if (typeof result === 'boolean') { - if (result) handleTabClick(props.name) + const { name: nameProp } = props + if (nameProp !== valueRef.value) { + if (nameProp === nextTabNameRef.value) return + nextTabNameRef.value = nameProp + const { value: onBeforeLeave } = onBeforeLeaveRef + if (!onBeforeLeave) { + handleTabClick(nameProp) } else { - result.then( - () => { - if ( - tabIdRef.value.tab === props.name && - tabIdRef.value.id === id - ) { - handleTabClick(props.name) - } - }, - () => { - // not allowed to change tab + void Promise.resolve( + (onBeforeLeave as OnBeforeLeaveImpl)(props.name, valueRef.value) + ).then((allowLeave) => { + if (allowLeave) { + handleTabClick(nameProp) } - ) + }) } } } diff --git a/src/tabs/src/Tabs.tsx b/src/tabs/src/Tabs.tsx index 4962ba529..519a88b23 100644 --- a/src/tabs/src/Tabs.tsx +++ b/src/tabs/src/Tabs.tsx @@ -28,8 +28,7 @@ import { Addable, OnClose, OnCloseImpl, - BeforeLeave, - BeforeLeaveImpl, + OnBeforeLeave, tabsInjectionKey, TabsType } from './interface' @@ -60,7 +59,7 @@ const tabsProps = { type: Number, default: 0 }, - onBeforeLeave: [Function, Array] as PropType>, + onBeforeLeave: Function as PropType, onAdd: Function as PropType<() => void>, 'onUpdate:value': [Function, Array] as PropType>, onUpdateValue: [Function, Array] as PropType>, @@ -138,10 +137,8 @@ export default defineComponent({ compitableValueRef, uncontrolledValueRef ) - const tabIdRef = ref<{ tab: string | number | null, id: number }>({ - tab: mergedValueRef.value, - id: 0 - }) + + const nextTabNameRef = { value: mergedValueRef.value } const tabWrapperStyleRef = computed(() => { if (!props.justifyContent || props.type === 'card') return undefined @@ -184,20 +181,9 @@ export default defineComponent({ updateBarStyle(tabEl) } } - function handleBeforeLeave ( - activeName: string | number, - oldActiveName: string | number | null - ): boolean | Promise { - const { onBeforeLeave } = props - if (!onBeforeLeave) return true - return (onBeforeLeave as BeforeLeaveImpl)(activeName, oldActiveName) - } function handleTabClick (panelName: string | number): void { doUpdateValue(panelName) } - function setTabId (tab: string | number, id: number): void { - tabIdRef.value = { tab, id } - } function doUpdateValue (panelName: string | number): void { const { onActiveNameChange, @@ -293,10 +279,9 @@ export default defineComponent({ typeRef: toRef(props, 'type'), closableRef: toRef(props, 'closable'), valueRef: mergedValueRef, - tabIdRef, - handleBeforeLeave, + nextTabNameRef, + onBeforeLeaveRef: toRef(props, 'onBeforeLeave'), handleTabClick, - setTabId, handleClose, handleAdd }) diff --git a/src/tabs/src/interface.ts b/src/tabs/src/interface.ts index 2f08076f4..5841b4e31 100644 --- a/src/tabs/src/interface.ts +++ b/src/tabs/src/interface.ts @@ -8,13 +8,13 @@ export type OnUpdateValueImpl = (value: string | number) => void export type OnClose = (name: string & number) => void export type OnCloseImpl = (name: string | number) => void -export type BeforeLeave = ( - activeName: string & number, - oldActiveName: string & number & null +export type OnBeforeLeave = ( + Name: string & number, + oldName: string & number & null ) => boolean | Promise -export type BeforeLeaveImpl = ( - activeName: string | number, - oldActiveName: string | number | null +export type OnBeforeLeaveImpl = ( + name: string | number, + oldName: string | number | null ) => boolean | Promise export interface TabsInjection { @@ -24,10 +24,9 @@ export interface TabsInjection { closableRef: Ref tabStyleRef: Ref paneStyleRef: Ref - tabIdRef: Ref<{ tab: string | number | null, id: number }> - handleBeforeLeave: BeforeLeaveImpl + nextTabNameRef: { value: string | number | null } + onBeforeLeaveRef: Ref handleTabClick: (panelName: string | number) => void - setTabId: (tab: string | number, id: number) => void handleClose: (panelName: string | number) => void handleAdd: () => void } From 7d153c3bb12001d67f93a1a28404162e81f376dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B9=90=E8=81=AA?= Date: Thu, 21 Oct 2021 00:12:21 +0800 Subject: [PATCH 10/12] fix(tabs): typo --- src/tabs/src/interface.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs/src/interface.ts b/src/tabs/src/interface.ts index 5841b4e31..54afef99b 100644 --- a/src/tabs/src/interface.ts +++ b/src/tabs/src/interface.ts @@ -9,7 +9,7 @@ export type OnClose = (name: string & number) => void export type OnCloseImpl = (name: string | number) => void export type OnBeforeLeave = ( - Name: string & number, + name: string & number, oldName: string & number & null ) => boolean | Promise export type OnBeforeLeaveImpl = ( From 358b279c826e3fbeebef652d5ab96d7fb03b1934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B9=90=E8=81=AA?= Date: Thu, 21 Oct 2021 00:52:35 +0800 Subject: [PATCH 11/12] fix(upload): file can't be removed when file count limit is reached, closes #1401 --- CHANGELOG.en-US.md | 4 ++++ CHANGELOG.zh-CN.md | 4 ++++ src/upload/src/Upload.tsx | 8 +++----- src/upload/src/UploadTrigger.tsx | 13 ++++++++++--- src/upload/src/interface.ts | 1 + 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 317baf86f..c81692bf5 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -2,6 +2,10 @@ ## Pending +## Fixes + +- Fix `n-upload`'s file can't be removed when file count limit is reached, closes [#1401](https://github.com/TuSimple/naive-ui/issues/1401). + ### Feats - `n-tabs` add `on-before-leave` prop, closes [#1337](https://github.com/TuSimple/naive-ui/issues/1337). diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 28ea0c630..c9fe01aa8 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -2,6 +2,10 @@ ## Pending +## Fixes + +- 修复 `n-upload` 在达到最大文件数量后无法删除文件,关闭 [#1401](https://github.com/TuSimple/naive-ui/issues/1401) + ### Feats - `n-tabs` 新增 `on-before-leave` 属性,关闭 [#1337](https://github.com/TuSimple/naive-ui/issues/1337) diff --git a/src/upload/src/Upload.tsx b/src/upload/src/Upload.tsx index 194b8a397..3b6d4b76d 100644 --- a/src/upload/src/Upload.tsx +++ b/src/upload/src/Upload.tsx @@ -282,11 +282,8 @@ export default defineComponent({ mergedClsPrefixRef ) const formItem = useFormItem(props) - const mergedDisabledRef = computed(() => { + const maxReachedRef = computed(() => { const { max } = props - if (formItem.mergedDisabledRef.value) { - return true - } if (max !== undefined) { return mergedFileListRef.value.length >= max } @@ -515,7 +512,8 @@ export default defineComponent({ openFileDialog, draggerInsideRef, handleFileAddition, - mergedDisabledRef, + mergedDisabledRef: formItem.mergedDisabledRef, + maxReachedRef, fileListStyleRef: toRef(props, 'fileListStyle'), abstractRef: toRef(props, 'abstract'), cssVarsRef diff --git a/src/upload/src/UploadTrigger.tsx b/src/upload/src/UploadTrigger.tsx index 0ecbe19b8..9a956dcfc 100644 --- a/src/upload/src/UploadTrigger.tsx +++ b/src/upload/src/UploadTrigger.tsx @@ -22,6 +22,7 @@ export default defineComponent({ const { mergedClsPrefixRef, mergedDisabledRef, + maxReachedRef, listTypeRef, dragOverRef, openFileDialog, @@ -34,7 +35,7 @@ export default defineComponent({ ) function handleTriggerClick (): void { - if (mergedDisabledRef.value) return + if (mergedDisabledRef.value || maxReachedRef.value) return openFileDialog() } function handleTriggerDragOver (e: DragEvent): void { @@ -51,7 +52,13 @@ export default defineComponent({ } function handleTriggerDrop (e: DragEvent): void { e.preventDefault() - if (!draggerInsideRef.value || mergedDisabledRef.value) return + if ( + !draggerInsideRef.value || + mergedDisabledRef.value || + maxReachedRef.value + ) { + return + } const dataTransfer = e.dataTransfer const files = dataTransfer?.files if (files) { @@ -74,7 +81,7 @@ export default defineComponent({
mergedDisabledRef: Ref + maxReachedRef: Ref abstractRef: Ref cssVarsRef: Ref submit: (fileId?: string) => void From d60b5a4af3834c2280d17f267c63ccb0d5fd43ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B9=90=E8=81=AA?= Date: Thu, 21 Oct 2021 01:23:43 +0800 Subject: [PATCH 12/12] 2.19.11 --- CHANGELOG.en-US.md | 2 +- CHANGELOG.zh-CN.md | 2 +- package.json | 2 +- src/version.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index c81692bf5..eb91e3ade 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -1,6 +1,6 @@ # CHANGELOG -## Pending +## 2.19.11 (2021-10-21) ## Fixes diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index c9fe01aa8..c60a578a4 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -1,6 +1,6 @@ # CHANGELOG -## Pending +## 2.19.11 (2021-10-21) ## Fixes diff --git a/package.json b/package.json index 1664da095..c08bcb6ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "naive-ui", - "version": "2.19.9", + "version": "2.19.11", "description": "A Vue 3 Component Library. Fairly Complete, Customizable Themes, Uses TypeScript, Not Too Slow", "main": "lib/index.js", "module": "es/index.js", diff --git a/src/version.ts b/src/version.ts index 5394f6302..eacf8b7f1 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export default '2.19.9' +export default '2.19.11'