From b3a3497de8ae4b44921e793e8134e902c2ed83c7 Mon Sep 17 00:00:00 2001 From: doom-9 <65016011+doom-9@users.noreply.github.com> Date: Sat, 10 Jul 2021 01:24:31 +0800 Subject: [PATCH] feat(carousel): add arrow prop (#451) * feat:n-input Support hidden password * feat(form): support require-mark-placement(#171) * Revert "feat(form): support require-mark-placement(#171)" This reverts commit 06277776933ed4e68b32d2651014458aca2e50f6. * Revert "feat:n-input Support hidden password" This reverts commit ea6491783dcc79e610534632a05b2894ded97494. * WIP * feat(carousel): add arrow prop * feat(carousel): fix code * feat(carousel): fix code and add test * feat(carousel): fix style * feat(carousel): add test --- CHANGELOG.en-US.md | 1 + CHANGELOG.zh-CN.md | 1 + src/carousel/demos/enUS/index.demo-entry.md | 2 + src/carousel/demos/enUS/show-arrow.demo.md | 30 +++++++++ src/carousel/demos/zhCN/index.demo-entry.md | 2 + src/carousel/demos/zhCN/show-arrow.demo.md | 30 +++++++++ src/carousel/src/Carousel.tsx | 31 +++++++++ src/carousel/src/styles/index.cssr.ts | 49 ++++++++++++++ src/carousel/tests/Carousel.spec.ts | 73 +++++++++++++++++++++ 9 files changed, 219 insertions(+) create mode 100644 src/carousel/demos/enUS/show-arrow.demo.md create mode 100644 src/carousel/demos/zhCN/show-arrow.demo.md diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 234fdacb7bc..93f98e1dd8a 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -18,6 +18,7 @@ - `n-tree` exports `TreeDragInfo` & `TreeDropInfo` type. - `n-empty` export `icon` slot. - `useDialog` option add `maskClosable` prop, closes [#420](https://github.com/TuSimple/naive-ui/issues/420). +- `n-carousel` add `show-arrow` prop. ### Fixes diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 7789791198f..ed9d9b2ae18 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -18,6 +18,7 @@ - `n-tree` 导出 `TreeDragInfo` & `TreeDropInfo` 类型 - `n-empty` 导出 `icon` slot - `useDialog` 选项增加 `maskClosable` 属性,关闭 [#420](https://github.com/TuSimple/naive-ui/issues/420) +- `n-carousel` 新增 `show-arrow` 属性 ### Fixes diff --git a/src/carousel/demos/enUS/index.demo-entry.md b/src/carousel/demos/enUS/index.demo-entry.md index d85c6bce684..007dfa288d9 100644 --- a/src/carousel/demos/enUS/index.demo-entry.md +++ b/src/carousel/demos/enUS/index.demo-entry.md @@ -9,6 +9,7 @@ basic autoplay hover dot-placement +show-arrow ``` ## API @@ -17,6 +18,7 @@ dot-placement | Name | Type | Default | Description | | --- | --- | --- | --- | +| show-arrow | `boolean` | `false` | Whether to show arrow button. | | autoplay | `boolean` | `false` | Whether to scroll automatically. | | interval | `number` | `5000` | Auto play interval. | | dot-placement | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | Dot placement in the panel. | diff --git a/src/carousel/demos/enUS/show-arrow.demo.md b/src/carousel/demos/enUS/show-arrow.demo.md new file mode 100644 index 00000000000..6c4d4a331ed --- /dev/null +++ b/src/carousel/demos/enUS/show-arrow.demo.md @@ -0,0 +1,30 @@ +# Show Arrow Button + +```html + + + + + + +``` + +```css +.carousel-img { + width: 100%; + height: 240px; + object-fit: cover; +} +``` diff --git a/src/carousel/demos/zhCN/index.demo-entry.md b/src/carousel/demos/zhCN/index.demo-entry.md index 62d7eb3302b..2e8e3d9437f 100644 --- a/src/carousel/demos/zhCN/index.demo-entry.md +++ b/src/carousel/demos/zhCN/index.demo-entry.md @@ -9,6 +9,7 @@ basic autoplay hover dot-placement +show-arrow ``` ## API @@ -17,6 +18,7 @@ dot-placement | 名称 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | +| show-arrow | `boolean` | `false` | 是否显示箭头按钮 | | autoplay | `boolean` | `false` | 是否自动播放 | | dot-placement | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | 轮播指示点位置 | | interval | `number` | `5000` | 自动播放的间隔 | diff --git a/src/carousel/demos/zhCN/show-arrow.demo.md b/src/carousel/demos/zhCN/show-arrow.demo.md new file mode 100644 index 00000000000..cc0efcdebc7 --- /dev/null +++ b/src/carousel/demos/zhCN/show-arrow.demo.md @@ -0,0 +1,30 @@ +# 显示箭头按钮 + +```html + + + + + + +``` + +```css +.carousel-img { + width: 100%; + height: 240px; + object-fit: cover; +} +``` diff --git a/src/carousel/src/Carousel.tsx b/src/carousel/src/Carousel.tsx index 0e6b45af0d2..f78e4562c45 100644 --- a/src/carousel/src/Carousel.tsx +++ b/src/carousel/src/Carousel.tsx @@ -18,12 +18,14 @@ import { useConfig, useTheme } from '../../_mixins' import type { ThemeProps } from '../../_mixins' import { flatten } from '../../_utils' import type { ExtractPublicPropTypes } from '../../_utils' +import { BackwardIcon, ForwardIcon } from '../../_internal/icons' import { carouselLight } from '../styles' import type { CarouselTheme } from '../styles' import style from './styles/index.cssr' const carouselProps = { ...(useTheme.props as ThemeProps), + showArrow: Boolean, autoplay: Boolean, dotPlacement: { type: String as PropType<'top' | 'bottom' | 'left' | 'right'>, @@ -271,6 +273,7 @@ export default defineComponent({ }, render () { const { + showArrow, dotPlacement, mergedClsPrefix, current, @@ -350,6 +353,34 @@ export default defineComponent({ ) })} + {showArrow && [ +
{ + this.next() + }} + > + +
, +
{ + this.prev() + }} + > + +
+ ]} ) } diff --git a/src/carousel/src/styles/index.cssr.ts b/src/carousel/src/styles/index.cssr.ts index 3853346b111..731a854e4c1 100644 --- a/src/carousel/src/styles/index.cssr.ts +++ b/src/carousel/src/styles/index.cssr.ts @@ -47,6 +47,55 @@ export default cB('carousel', ` margin-right: 0; `) ]), + cE('arrow', ` + position: absolute; + transition: transform .1s var(--bezier); + transform: scale(1); + cursor: pointer; + height: 50px; + width: 50px; + display: flex; + align-items: center; + justify-content: center; + color: var(--dot-color-active); + `, [ + cM('right', ` + transform: translateY(-50%); + top: 50%; + right: 0; + `, [ + c('&:hover', { + transform: 'translateY(-50%) scale(1.1)' + }) + ]), + cM('left', ` + transform: translateY(-50%); + top: 50%; + left: 0; + `, [ + c('&:hover', { + transform: 'translateY(-50%) scale(1.1)' + }) + ]), + cM('top', ` + transform: translateX(-50%) rotate(90deg); + top: 0; + left: 50%; + `, [ + c('&:hover', { + transform: 'translateX(-50%) scale(1.1) rotate(90deg)' + }) + ]), + cM('bottom', ` + transform: translateX(-50%) rotate(90deg); + bottom: 0; + left: 50%; + `, [ + c('&:hover', { + transform: 'translateX(-50%) scale(1.1) rotate(90deg)' + }) + ]) + ]), cM('left', [ cE('slides', ` flex-direction: column; diff --git a/src/carousel/tests/Carousel.spec.ts b/src/carousel/tests/Carousel.spec.ts index abd7ce9f513..8ec4d7f6141 100644 --- a/src/carousel/tests/Carousel.spec.ts +++ b/src/carousel/tests/Carousel.spec.ts @@ -1,5 +1,7 @@ +import { h, nextTick } from 'vue' import { mount } from '@vue/test-utils' import { NCarousel } from '../index' +import { sleep } from 'seemly' describe('n-carousel', () => { it('should work with import on demand', () => { @@ -15,4 +17,75 @@ describe('n-carousel', () => { ) } }) + + it('should work with `showArrow` prop', async () => { + const wrapper = mount(NCarousel) + + const dotToArrow = [ + { + dot: ['top', 'bottom'], + arrow: ['left', 'right'] + }, + { + dot: ['left', 'right'], + arrow: ['top', 'bottom'] + } + ] + + for (const item of dotToArrow) { + for (const dotItem of item.dot) { + await wrapper.setProps({ showArrow: true, dotPlacement: dotItem }) + + expect( + wrapper.find(`.n-carousel__arrow--${item.arrow[0]}`).exists() + ).toBe(true) + expect( + wrapper.find(`.n-carousel__arrow--${item.arrow[1]}`).exists() + ).toBe(true) + } + } + }) + + it('arrow button should work', async () => { + const wrapper = mount(NCarousel, { + slots: { + default: () => { + return [ + h('img', { + style: 'width: 100%; height: 240px; object-fit: cover;', + src: 'https://s.anw.red/news/1623152423.jpg!/both/800x450/quality/78/progressive/true/ignore-error/true' + }), + h('img', { + style: 'width: 100%; height: 240px; object-fit: cover;', + src: 'https://s.anw.red/news/1623152423.jpg!/both/800x450/quality/78/progressive/true/ignore-error/true' + }) + ] + } + } + }) + + await wrapper.setProps({ + showArrow: true + }) + + const slidesDOMArray = wrapper.find('.n-carousel__slides').findAll('div') + + 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') + }) + }) + }) + }) })